I'm reading the book on subject.
In 5.18, Brian Goetz gave an example of semi-efficient memoizer with a non-volatile shared variable cache
having the type of ConcurrentHashMap as follows:
public class Memoizer3<A, V> implements Computable<A, V> {
private final Map<A, Future<V>> cache
= new ConcurrentHashMap<A, Future<V>>();
private final Computable<A, V> c;
public Memoizer3(Computable<A, V> c) { this.c = c; }
public V compute(final A arg) throws InterruptedException {
Future<V> f = cache.get(arg);
if (f == null) {
Callable<V> eval = new Callable<V>() {
public V call() throws InterruptedException {
return c.compute(arg);
}
};
FutureTask<V> ft = new FutureTask<V>(eval);
f = ft;
cache.put(arg, ft); // Can it be put at the very beginning of compute?
ft.run();
}
try {
return f.get();
} catch (ExecutionException e) {
throw launderThrowable(e.getCause());
}
}
}
The problem is that I don't understand rules under which cache.put(arg, ft);
can be reordered by a compiler to be put ahead of Future<V> f = cache.get(arg);
in terms of JLS (Is reordering of cache variable is possible at all?).
Under "reordering", I mean a chance of that lines of complete code may be reordered by a compiler due to enabled optimizations.
The question does not touch the topic of CPU memory reordering, which is highlighted, e.g., in https://stackoverflow.com/a/66973124
EDIT:
A reason for this question is the ability of a compiler to damage unsynchronized multithreaded code fragments using shared variables in some cases, another reason is a quotation from an author of this book, Doug Lea:
The within-thread as-if-serial property is helpful only when only one thread at a time is manipulating variables, due to synchronization, structural exclusion, or pure chance. When multiple threads are all running unsynchronized code that reads and writes common fields, then arbitrary interleavings, atomicity failures, race conditions, and visibility failures may result in execution patterns that make the notion of as-if-serial just about meaningless with respect to any given thread.
Even though JLS addresses some particular legal and illegal reorderings that can occur, interactions with these other issues reduce practical guarantees to saying that the results may reflect just about any possible interleaving of just about any possible reordering. So there is no point in trying to reason about the ordering properties of such code.
Per http://gee.cs.oswego.edu/dl/cpj/jmm.html
In other words, not following the JLS constraints regarding "happens-before", locks or volatile semantics may lead to broken results in unsynchronized code which uses shared variables.
P.S. Thanks to Peter Cordes for his comments on this theme.