Th reason nothing happens without the System.out.println("here");
is well explained by Cameron Skinner's answer.
So why does the block inside the if(x!=0)
works when println
is used? println
executes a synchronized
block (see PrintStream.write(String s)
). This forces the current thread to retrieve System.out
state from the main memory and update the thread's cache, before letting the thread to execute any further line of code. The surprising side effect, is that also states of other variables, such as your x
, are also updated in this manner, although x
's lock was not involved in the synchronization. It's called piggybacking.
If I'll use free text to describe the formalities described in the Java Memory Model Specification: it is said that operations executed before a release of a lock happen-before operations executed after the next obtaining of that lock.
I'll demonstrate it with an example. Assume that Thread 1
is executed and only when it finishes, Thread 2
is started. Also assume that x
, y
and z
are variables shared by both threads. Note that we can determine z
's value only inside the synchronized
block of y
.
Thread 1:
x = 0;
synchronized(y) {
}
Thread 2:
x = 1
z = x;
// here there's no guarantee as to z value, could be 0 or 1
synchronized(y) {
z = x;
// here z has to be 0!
}
This is of course a very bad practice to rely on for synchronization...