I have encountered the following code when reading Vavr's Lazy
source code:
private transient volatile Supplier<? extends T> supplier;
private T value; // will behave as a volatile in reality, because a supplier volatile read will update all fields (see https://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#volatile)
public T get() {
return (supplier == null) ? value : computeValue();
}
private synchronized T computeValue() {
final Supplier<? extends T> s = supplier;
if (s != null) {
value = s.get();
supplier = null;
}
return value;
}
This is a famous pattern called "Double-checked locking", but it looks broken for me. Suppose we embed this code in a multithreaded environment. If the get()
method is called by the first thread and the supplier construct a new object, (for me) there is a possibility for another thread to see the semi-constructed object due to reordering of the following code:
private synchronized T computeValue() {
final Supplier<? extends T> s = supplier;
if (s != null) {
// value = s.get(); suppose supplier = () -> new AnyClass(x, y , z)
temp = calloc(sizeof(SomeClass));
temp.<init>(x, y, z);
value = temp; //this can be reordered with line above
supplier = null;
}
return value;
}
Unfortunately, there is a comment next to the value
field:
private transient volatile Supplier<? extends T> supplier;
private T value; // will behave as a volatile in reality, because a supplier volatile read will update all fields (see https://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#volatile)
As far as I know, a volatile read will "refresh" values of variables that are read after a volatile read. In other words - it drains the cache's invalidation queue (if we talk about MESI coherence protocol). Additionally, it prevents loads/reads that happen after the volatile read to be reordered before it. Still, it doesn't give any guarantee that instructions in object creation (calling supplier get()
method) will not be reordered.
My question is - why this code is considered thread-safe?
Obviously, I haven't found anything interesting in the source placed in the comment.