0

我有一个非常简单的代码,但无法理解。

    public class Test extends Thread {
    
        public synchronized void testPrint() {
            System.out.println("I am sleeping..."
                    + Thread.currentThread().getName());
            try {
                Thread.sleep(3000);
                System.out.println("I am done sleeping..."
                        + Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        public void run() {
            Test t = new Test();
            t.testPrint();
    
            System.out.println("I am out..." + Thread.currentThread().getName());
        }
    
        public static void main(String[] args) {
            Test t1 = new Test();
            Test t2 = new Test();
    
            t1.start();
            t2.start();
    
        }
    }

这是我的问题

当两个线程执行时Test t = new Test(),这是否会创建两个具有相同名称的不同对象?在多线程的这条线上会发生什么?

我得到低于结果,

我在睡觉……Thread-0

我在睡觉... Thread-1

我睡完了……Thread-0

我出去了……Thread-0

我睡完了……Thread-1

我出去了……Thread-1


从输出来看,这肯定意味着创建了两个对象,这就是为什么两个线程都可以进入同步方法的原因。希望我的理解是正确的?系统如何维护这两个对象?

4

4 回答 4

2

您正在创建两个不同的对象,它们将具有两个不同的监视器,将在其上获取锁。由于两个线程都在不同的对象上工作,因此不会出现同步。

你可以试试

public class Test extends Thread {

Object obj;

public Test(Object obj){
    this.obj = obj;
}

public synchronized void testPrint() {
    System.out.println("I am sleeping..."
            + Thread.currentThread().getName());
    try {
        Thread.sleep(3000);
        System.out.println("I am done sleeping..."
                + Thread.currentThread().getName());
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

public void run() {
    ((Test)obj).testPrint();
    System.out.println("I am out..." + Thread.currentThread().getName());
}

public static void main(String[] args) {

    Object obj = new Test(null);

    Test t1 = new Test(obj);
    Test t2 = new Test(obj);

    t1.start();
    t2.start();

}
}

输出是

I am sleeping...Thread-1
I am done sleeping...Thread-1
I am out...Thread-1
I am sleeping...Thread-2
I am done sleeping...Thread-2
I am out...Thread-2

正如预期的那样。

于 2013-11-01T05:30:58.003 回答
2

使用您当前的方法,您可以确保该Test方法的每个实例testPrint()不能同时运行。这一切都取决于你想做什么。我假设您想保护该testPrint()方法不同时在多个线程中运行,并具有多个Test.

目前,您synchronized直接在方法上使用关键字。这导致使用对象本身( 的实例Test)用于同步。

您应该在实例之间共享的另一个对象上进行同步Test(例如,您可以使锁定对象成为静态)。

另请注意,通常只实现Runnable接口然后将实现传递给线程是一个更好的主意。另外,您不必Test每次运行时都创建一个新实例(我看不到这样做的目的),我对此进行了评论。

public class Test extends Thread {
  // could also use a static monitor instead.
  // private static final Object monitor = new Object();
  private final Object monitor;

  public Test(final Object monitor) {
    this.monitor = monitor;
  }

  public void testPrint() {
    synchronized (monitor) {
      System.out.println("I am sleeping..." + Thread.currentThread().getName());
      try {
        Thread.sleep(3000);
        System.out.println("I am done sleeping..." + Thread.currentThread().getName());
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }

  public void run() {
    //Test t = new Test(monitor);
    //t.testPrint();
    testPrint();
    System.out.println("I am out..." + Thread.currentThread().getName());
  }

  public static void main(String[] args) {
    // synchronization will happen on this object.
    final Object monitor = new Object();

    Test t1 = new Test(monitor);
    Test t2 = new Test(monitor);

    t1.start();
    t2.start();

  }
}
于 2013-11-01T08:34:19.617 回答
1

当您运行Test t = new Test()jvm 在堆上创建新对象并将带有指向该对象的链接的变量 t 放在当前线程的堆栈上。
当您在两个或多个不同线程中运行该代码时,每个线程都有自己的堆栈,因此每个线程都创建自己的变量 t 和对象 Test

于 2013-11-01T05:34:46.083 回答
0
Test t = new Test()

这将在堆中创建一个对象,并且引用将被放置在堆栈中。

在您的示例中,您根本不需要该synchronized方法,因为您没有在不同线程之间共享实例。

于 2013-11-01T05:38:59.733 回答