Concurrency
Sharing Objects: Visibility & Publication
- No synchronization ⇒ no visibility guarantee: stale reads, reorderings, infinite loops
volatileguarantees visibility (and ordering) for a single variable — not atomicity of compound ops- Safe publication: static initializer,
volatile/AtomicReference,finalfields, or a lock/concurrent collection finalfields are visible correctly after construction — immutable objects publish safely through anything- Never let
thisescape during construction (listeners, inner classes starting threads)
public class NoVisibility {
private static boolean ready;
private static int number;
static void reader() {
while (!ready) Thread.onSpinWait(); // may loop FOREVER (stale read)
System.out.println(number); // may print 0 (reordering!)
}
public static void main(String[] a) {
new Thread(NoVisibility::reader).start();
number = 42;
ready = true; // unsynchronized writes
}
}Both failures are legal outcomes: the JIT may hoist ready out of the loop, and the CPU/compiler may reorder the writes (Java Memory Model, Hardware Memory). Declaring ready volatile fixes both — a volatile write happens-before the read that sees it, dragging number = 42 into view with it.
private volatile boolean shutdownRequested; // one writer, many readers: perfect
public void shutdown() { shutdownRequested = true; }
while (!shutdownRequested) { doWork(); }
private volatile int hits;
hits++; // STILL A RACE — volatile read + write, not atomic RMWSafe publication
Publishing = making an object visible to other threads. Done unsafely (plain field write), another thread can observe the reference before the constructor's writes — a half-built object. The safe idioms (JCiP 3.5): initialize in a static initializer; store into volatile/AtomicReference; store into a final field of a properly published object; or hand it over via a lock-guarded field or concurrent collection (a BlockingQueue between producer and consumer is a safe-publication conveyor belt).