我试图理解java中的同步。我有以下示例

public class TestThr implements Runnable {

   public static void main(String[] args) {

            Thread t=new Thread(new TestThr());
            Thread t1=new Thread(new TestThr());

            t.start();
            t1.start();
   }

   @Override
   public void run() {
        sync();
   }

   public synchronized void sync(){
         for (int i=0;i<10;i++){
            System.out.println("Running "+Thread.currentThread().getName());
        }
   }

 }

输出 :
运行线程-0
运行线程1
运行线程-0
运行线程1
运行线程-0
运行线程1
运行线程1
运行线程1
运行线程-0
运行线程1
运行线程1
运行线程1
运行线程1
运行线程1
运行线程-0
运行线程-0
运行线程-0
运行线程-0
运行线程-0
运行线程-0

从上面的示例中,我期望一个线程(无论谁先输入)都将完成迭代,然后第二个线程将开始并完成,但是输出不一致。

请补充您的意见。

提前致谢。

最佳答案



您得到的输出是您不理解的,但它与您编写的代码一致。当您具有synchronized方法时,您将锁定封闭类的实例。

public class TestThr implements Runnable {
   ...
   public synchronized void sync() {

在您的示例中,sync方法为synchronized,因此它将锁定在TestThr的特定实例上。您正在像这样启动线程:
Thread t = new Thread(new TestThr());
Thread t1 = new Thread(new TestThr());

这意味着每个线程都有自己的TestThr实例,因此它们锁定在不同的实例上并且不会彼此停止运行。

如果您改为执行以下操作:
final TestThr testThr = new TestThr();
Thread t = new Thread(testThr);
Thread t1 = new Thread(testThr);

现在,这两个线程正在TestThr的同一实例上工作,因此它们将锁定在同一对象上,并且您的输出将达到您的期望。

这仅适用,因为TestThr没有存储任何字段。如果您需要一个更复杂的类,那么我将一个锁对象传递给他们。就像是:
final Object lockObject = new Object();
Thread t = new Thread(new TestThr(lockObject));
Thread t1 = new Thread(new TestThr(lockObject));

然后,在您的代码中执行以下操作:
public void sync() {
   synchronized (lockObject) {
      ...

因此,该方法不会被锁定,但是您将在共享锁定对象上进行同步。

顺便说一句,考虑到循环的大小,一个线程很有可能会启动并运行循环,然后在另一个线程甚至启动之前退出。放置System.out.println(...)调用会减慢线程速度,因此可能会引起争用,但是如果删除输出,则需要担心。由于线程之间的竞争状况,可能很难测试像这样的线程程序。

10-05 22:41