Concurrency

Sharing Objects: Visibility & Publication

Locking is not only mutual exclusion — it is memory visibility. Without synchronization, one thread's writes may never become visible to another, in any order. Publish objects safely or watch them arrive half-constructed.
  • No synchronization ⇒ no visibility guarantee: stale reads, reorderings, infinite loops
  • volatile guarantees visibility (and ordering) for a single variable — not atomicity of compound ops
  • Safe publication: static initializer, volatile/AtomicReference, final fields, or a lock/concurrent collection
  • final fields are visible correctly after construction — immutable objects publish safely through anything
  • Never let this escape during construction (listeners, inner classes starting threads)
The visibility failure (JCiP Listing 3.1)
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.

volatile: the flag idiom (and its limit)
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 RMW

Safe 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).

Sources
  • Java Concurrency in PracticeCh. 3 — Sharing Objects
  • Core Java, Volume I: Fundamentals (13th ed.)Ch. 10.5 — Synchronization (visibility)
  • Effective Java (3rd ed.)Item 78