Doug Lea is right. You can find the relevant part in section §17.4.4 of the Java Language Specification:
§17.4.4 Synchronization Order
[..] A write to a volatile variable v (§8.3.1.4) synchronizes-with all subsequent reads of v by any thread (where “subsequent” is defined according to the synchronization order). [..]
The memory model of the concrete machine doesn’t matter, because the semantics of the Java Programming Language are defined in terms of an abstract machine — independent of the concrete machine. It’s the responsibility of the Java runtime environment to execute the code in such a way, that it complies with the guarantees given by the Java Language Specification.
Regarding the actual question:
- If there is no further synchronization, the method
read2
can print"Bar"
, becauseread2
can be executed beforewrite
. - If there is an additional synchronization with a
CountDownLatch
to make sure thatread2
is executed afterwrite
, then methodread2
will never print"Bar"
, because the synchronization withCountDownLatch
removes the data race onx
.
Independent volatile variables:
Does it make sense, that a write to a volatile variable does not synchronize-with a read of any other volatile variable?
Yes, it makes sense. If two threads need to interact with each other, they usually have to use the same volatile
variable in order to exchange information. On the other hand, if a thread uses a volatile variable without a need for interacting with all other threads, we don’t want to pay the cost for a memory barrier.
It is actually important in practice. Let’s make an example. The following class uses a volatile member variable:
class Int {
public volatile int value;
public Int(int value) { this.value = value; }
}
Imagine this class is used only locally within a method. The JIT compiler can easily detect, that the object is only used within this method (Escape analysis).
public int deepThought() {
return new Int(42).value;
}
With the above rule, the JIT compiler can remove all effects of the volatile
reads and writes, because the volatile
variable can not be accesses from any other thread.
This optimization actually exists in the Java JIT compiler:
- src/share/vm/opto/memnode.cpp