JVM & Memory

98. Java Memory Model & Happens-Before Guarantee

The Java Memory Model (JMM) defines how threads interact through shared memory; the happens-before relationship guarantees that memory writes by one thread are visibly observed by another without instruction reordering.

Java 21 (JLS Chapter 17)

Explanation

Modern CPUs use multi-level hardware caches, store buffers, and out-of-order execution, while JIT compilers aggressively reorder instructions for performance. Without a formal specification, code running correctly on one architecture could read stale or half-initialized values on another. The Java Memory Model (JMM), codified in JLS §17.4, defines the exact rules under which a read of a variable is guaranteed to see a previous write.

The core concept is the happens-before order. If action A happens-before action B, then A's writes are visible to B and A is perceived to occur before B. Key happens-before rules in Java include: 1. Program order rule: Within a single thread, each action happens-before any subsequent action in program order. 2. Monitor lock rule: An unlock on a monitor lock happens-before every subsequent lock on that same monitor. 3. Volatile variable rule: A write to a volatile field happens-before every subsequent read of that same field. 4. Thread start rule: A call to Thread.start() happens-before any action in the started thread. 5. Thread termination rule: Any action in a thread happens-before any other thread successfully detects that thread has terminated (via join() or isAlive() == false). 6. Transitivity: If A happens-before B, and B happens-before C, then A happens-before C.

Without a happens-before link between a write and a read, the program contains a data race, and the JVM is permitted to observe stale data or out-of-order writes.

Example

public class HappensBeforeDemo {
    private int data = 0;
    private volatile boolean ready = false;

    // Thread 1: Writer
    public void writeData() {
        data = 42;           // 1. Normal write
        ready = true;        // 2. Volatile write (acts as a write-barrier)
        // By JMM: 1 happens-before 2 (program order).
        // Any subsequent read of 'ready' that sees true creates a happens-before link!
    }

    // Thread 2: Reader
    public void readData() {
        if (ready) {         // 3. Volatile read (acts as a read-barrier)
            // By JMM: 2 happens-before 3.
            // Transitivity: 1 happens-before 2 happens-before 3 happens-before 4!
            System.out.println("Data: " + data); // 4. Guaranteed to print 42, NEVER 0!
        }
    }
}

Sources