Using JDK 9 Memory Order Modes
gee.cs.oswego.edu
gee.cs.oswego.edu
I think it's important to emphasise this. You should think extremely carefully before reaching for features like these and should have a very good reason for not using the existing concurrency tools and data structures. That said, if you do need to build your own concurrent data structures then these do provide excellent primitives with which to do it.
It also makes heavy use of the JDK's concurrent maps, latches, and other structures which it would probably be unwise to try and re-implement.
In Java generics are erased at runtime, so the reference updater code has some supplementary runtime checks.
It's an instanceof check, if the class of the field is final (or can be proven to be effectively final by CHA) then it's a null check follow by a pointer check. Theoretically, the null check can proved to be unnecessary, be fused with another or be transformed to an implicitly nullcheck but in specific the case of an AtomicReferenceFieldUpdater, null is usually a valid value (by example, null is used as tombstone in many concurrent data structure implementations) so it's usually more than just a getClass() and a pointer check.
Here we go: https://www.google.com/webhp?sourceid=chrome-instant&ion=1&e...
Interestingly, there's no equivalent to C++ `acq_rel` on the RMW operations -- you have to either choose the stronger `volatile` ordering, or do a release fence followed by an acquire RMW (or the reverse).
Regular loads/stores may be mixed with atomic ones, but don't give any coherence or forward progress guarantees, and may see word tearing for longs or doubles.
The java `fullFence()` is stronger than a C++ `seq_cst` one; inserting one between every pair of Opaque accesses gives them sequential consistency (though, I understand that C++ is probably going to strengthen the semantics of `seq_cst` fences eventually).
and you can also do all memory operations on arrayish values (array or ByteBuffer) even un-aligned acces.
This is why the common pattern of double-checked locking is bad. This is:
class Thing {
private Thing thing = null;
public Thing getThing() {
if (thing == null) {
synchronized (this) {
if (thing == null) {
thing = new Thing();
}
}
}
return thing;
}
}
Don't do that. You could get hold of a partially-constructed Thing."The initial load (i.e., the very first encounter by a thread) of a final field cannot be reordered with the initial load of the reference to the object containing the final field. This comes into play in: x = sharedRef; ... ; i = x.finalField; A compiler would never reorder these since they are dependent, but there can be consequences of this rule on some processors."
Note that there are no constraints placed on sharedRef. It does not need to be volatile, for instance.
This link also has more useful info and examples: https://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.ht...
Right - I think the processor can still reorder. I've never been sure why the compiler is not allowed to reorder in this case, since this doesn't help you if the processor will do it anyway.
In the example you're mentioning if "Thing" is built with finals or if it is synchronized, then it can't have problems.
And given that "Thing" in this sample is meant to be accessed by multiple threads, then if that access isn't synchronized, then the double-checked pattern is not going to be your only problem ;-)
Basically when assigning a new object to a reference, the only way to know for sure that its internals are initialized before the assignment is to either work with finals or to synchronize that internal state.
It only works with the updated semantics of volatile (Java 5+), otherwise you're right.