Reputation: 1107
I observed a scenario where use of synchronized method or synchronized block producing different results. From below code:
class Callme {
void call(String msg) {
System.out.print("[" + msg);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("]");
}
}
class Caller implements Runnable{
String msg;
Callme target;
Thread t;
public Caller(Callme target, String msg) {
this.target = target;
this.msg = msg;
t = new Thread(this, "Caller thread");
t.start();
}
@Override
public void run() {
synchronized(target) {
target.call(msg);
new Callme().call(msg);
}
}
}
public class Test {
public static void main(String[] args) throws InterruptedException {
Callme obj = new Callme();
new Caller(obj, "thread1");
new Caller(obj, "thread2");
new Caller(obj, "thread3");
Thread.currentThread().join();
}
}
When I use the synchronized block in the Caller::run method the ouput is synchronized as below:
[thread1]
[thread1]
[thread3]
[thread3]
[thread2]
[thread2]
But when I use the synchronized method for the Callme::call method, instead of synchronized block, the output is not synchronized:
[thread1]
[thread1[thread2]
]
[thread3[thread2]
]
[thread3]
My Expectation is the output should not be synchronized on both cases because I am using different objects when calling the "Callme::call" method
This made me question my understanding of the Synchronized block concept?
Upvotes: 0
Views: 151
Reputation: 108939
A synchronized method is equivalent to a synchronized(this)
-block for the length of the entire method, however your code is using synchronized(target)
, and target
is a shared instance of Callme
. In other words: the object being synchronized on is different, so the behavior is not the same.
In the case you use synchronized(target)
, it means that all threads synchronize on the same instance of Callme
so their behavior is serial: a thread will hold the monitor of that Callme
instance for the whole duration of the Caller.run
method, so in effect the threads are executed one after the other.
In the case of a synchronized method, the threads each synchronize on their own instance of Caller
, so in effect there is no serialization (except for the writes to System.out
).
Some additional remarks:
Thread.currentThread().join()
is a bad idea, because it will wait on itselfThread
instances in the Runnable
implementation that is going to be run by that thread: you lose access to the thread. Especially don't do this in the constructor, because you are publishing a partially constructed object to the Thread
, which is not a big problem in this code, but might lead to subtle bugs in more complex applications.Upvotes: 1