In the following code:
class A {
private int number;
public void a() {
number = 5;
}
public void b() {
while(number == 0) {
// ...
}
}
}
If method b is called and then a new thread is started which fires method a, then method b is not guaranteed to ever see the change of number
and thus b
may never terminate.
Of course we could make number
volatile
to resolve this. However for academic reasons let's assume that volatile
is not an option:
The JSR-133 FAQs tells us:
After we exit a synchronized block, we release the monitor, which has the effect of flushing the cache to main memory, so that writes made by this thread can be visible to other threads. Before we can enter a synchronized block, we acquire the monitor, which has the effect of invalidating the local processor cache so that variables will be reloaded from main memory.
This sounds like I just need both a
and b
to enter and exit any synchronized
-Block at all, no matter what monitor they use. More precisely it sounds like this...:
class A {
private int number;
public void a() {
number = 5;
synchronized(new Object()) {}
}
public void b() {
while(number == 0) {
// ...
synchronized(new Object()) {}
}
}
}
...would eliminate the problem and will guarantee that b
will see the change to a
and thus will also eventually terminate.
However the FAQs also clearly state:
Another implication is that the following pattern, which some people use to force a memory barrier, doesn't work:
synchronized (new Object()) {}
This is actually a no-op, and your compiler can remove it entirely, because the compiler knows that no other thread will synchronize on the same monitor. You have to set up a happens-before relationship for one thread to see the results of another.
Now that is confusing. I thought that the synchronized-Statement will cause caches to flush. It surely can't flush a cache to main memory in way that the changes in the main memory can only be seen by threads which synchronize on the same monitor, especially since for volatile which basically does the same thing we don't even need a monitor, or am I mistaken there? So why is this a no-op and does not cause b
to terminate by guarantee?