简体   繁体   中英

Why this is not right by using synchronized (Java concurrency) in this example?

I have two Java classes as below...

(1) JavaClass SyncTest: It defines a class (implementing Runnable) and invokes a "synchronized" method (named "call") defined in Class SyncTestCalled

(2) JavaClass SyncTestCalled : There is one synchronized method.

------
    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]

What's wrong with the codes? Please help. Thanks a lot!


    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

When you use synchronized as part of the method declaration, Java attempts to acquire the monitor (lock) on the object the method is invoked on. So a method like

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

is equivalent to

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

In your code, you create three different SyncTestCalled objects and pass each individual one to the different SyncTest instances. In other words, nothing is coordinated. Each call to

syncTestCalled.call(this.name);

is synchronized on a different object and therefore none of the threads need to wait on the others.

It's up to the Thread scheduler who gets where first, so you get output like

[[[Two]
Three]
One]

or

[[[OneThree]
Two]
]

Note that Thread.sleep(long) does not relinquish any monitors the thread currently has.

Only one thread can invoke your call() method on a given instance at any given time. But what you want is atomicity for several calls to System.out.print() methods. For that, you need to acquire a lock on System.out instead:

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

Because PrintStream locks on itself, this will prevent other threads from interleaving their own calls to print() .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM