为什么在这个例子中使用synchronized(Java并发)是不对的?

时间:2014-01-13 03:15:54

标签: java multithreading

我有两个Java类,如下所示......

(1)JavaClass SyncTest:它定义一个类(实现Runnable)并调用Class SyncTestCalled中定义的“synchronized”方法(名为“call”)

(2)JavaClass SyncTestCalled:有一个同步方法。

------
    After calling from main(), I am thinking it should output something like:  
[Two]
[Three]
[One]

But, it outputs something like this (note the open bracket which is not paired in right locations) : 

[[[Two]
Three]
One]

代码有什么问题?请帮忙。非常感谢!


    Here is the code of these two classes...


    public class SyncTest implements Runnable {    
        Thread t;   
        String name;
        SyncTestCalled syncTestCalled;    
        public SyncTest(String name) {
                t = new Thread(this, name);
                syncTestCalled = new SyncTestCalled();
                this.name = name;
                t.start();
        }    
        public void run() {             
                syncTestCalled.call(this.name);
        }       
        public static void main(String[] args) {
                SyncTest syncTest1 = new SyncTest("One");
                SyncTest syncTest2 = new SyncTest("Two");
                SyncTest syncTest3 = new SyncTest("Three");
        }   
      } // of class SyncTest
    public class SyncTestCalled {
        public SyncTestCalled() {
        // Do nothing
        }    
        synchronized public void call(String message) {
                System.out.print("[");
                try {
                     Thread.sleep(1000);
                     System.out.print(message);
                } catch (InterruptedException e) { 
                     e.printStackTrace();
                }
                System.out.println("]");
        }
    } // of class SyncTestCalled

2 个答案:

答案 0 :(得分:3)

当您使用synchronized作为方法声明的一部分时,Java会尝试获取调用该方法的对象上的监视器(锁定)。所以像

这样的方法
synchronized public void call(String message) {
    ...
}

相当于

public void call(String message) {
    synchronized (this) {
        ...
    }
}

在您的代码中,您创建三个不同的SyncTestCalled对象,并将每个对象传递给不同的SyncTest实例。换句话说,没有任何协调。每次致电

syncTestCalled.call(this.name);

在不同的对象上同步,因此没有线程需要等待其他对象。

由线程调度程序首先获得位置,因此您可以获得类似

的输出
[[[Two]
Three]
One]

[[[OneThree]
Two]
]

请注意Thread.sleep(long)不会放弃线程当前拥有的任何监视器。

答案 1 :(得分:0)

在任何给定时间,只有一个线程可以在给定实例上调用您的call()方法。但是你想要的是几次调用System.out.print()方法的原子性。为此,您需要获取System.out上的锁定:

synchronized (System.out) {
  System.out.print('[');
  System.out.print(message);
  System.out.println(']');
}

因为PrintStream会锁定自身,这会阻止其他线程将自己的调用交错到print()