I was going through some simple examples on threading/synchronizing from a book that claims the use of synchronized
will allow access to the method by one thread being called on the same instance. It does serialize as promised but it seems that about 9/10 times the third Caller
created in the Synch
main
method below comes before the second. This code is the example code showing the issues without a synchronized method.
class CallMe {
void call(String msg) {
System.out.print("[" + msg);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("CallMe Interrupted");
}
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);
t.start();
}
@Override
public void run() {
target.call(msg);
}
}
class Synch {
public static void main(String args[]) {
CallMe target = new CallMe();
Caller c1 = new Caller(target, "Hello");
Caller c2 = new Caller(target, "Synchronized");
Caller c3 = new Caller(target, "World");
try {
c1.t.join();
c2.t.join();
c3.t.join();
} catch (InterruptedException e) {
System.out.println("Synch Interrupted");
}
}
}
The book shows two ways to deal with the issue, they are -
synchronized void call(String msg) {...}
and
public void run() { synchronized (target) {...} }
It's clear that both options work because, as opposed to the original code, the bracketed words are consistent like...
[Hello]
[World] (about 90% of the time the calls are backwards)
[Synchronized](1/many have Synchronized as the first msg)
...there's no rhyme or reason to the original code. So I know it's "working" and can be seen directly by placing breakpoints on each of the Caller
instantiations. It works every time, obviously to me, when I do.
Why is the third Caller
consistently calling call
before the second?