Reputation: 3
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
Upvotes: 0
Views: 74
Reputation: 269667
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()
.
Upvotes: 0
Reputation: 279950
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.
Upvotes: 3