To answer question (1), you are right with everything that you said about memory barriers, etc. (although the explanation is incomplete). Memory contamination ensures the ordering of ALL loads / storages in front of it, and not just volatile ones). However, iffy code example.
Thread operations should streamline them. Using the volatile operation at the beginning of your code in this way is redundant because it does not give any meaningful assurances regarding the order (I mean that it provides assurances, they are just very fragile).
Consider this example:
public void thread1() {
No matter what we do on thread2, there is absolutely no assurance that what is happening in thread1 is free to do almost anything it wants. Even if you use volatile operations on thread1, the ordering will not be visible on thread2.
To fix this, we need to order entries on thread1 with a memory barrier (also called unstable operation);
public void thread1() { counter1 = someVal;
In this example, the ordering is handled by thread1, but depends on the state of the flag. Thus, we only need to check the state of the flag , but you do not need another memory barrier for this reading (otherwise you need to check the volatile field, it just does not need the memory barrier).
So, to answer your question (2): The JVM expects you to use a mutable operation to streamline previous operations on a given thread. The reason your first unstable job doesn't have a memory barrier is because it doesn't affect whether your code will work (there may be situations where it's possible, but I can't think of anything, not to mention about any where it would be nice).
source share