Q31 of 40 · Core Java
Explain the Java Memory Model and the happens-before relationship.
Short answer
Short answer: The Java Memory Model (JMM) defines the rules for when one thread's writes are guaranteed to be visible to another thread. It does this through the happens-before (HB) partial order: if action A happens-before action B, then A's effects are visible to B. Without an HB edge, the JVM and CPU are free to reorder or cache writes invisibly.
Detail
Why HB is needed Modern CPUs use store buffers, caches, and out-of-order execution. Without explicit HB edges, Thread 2 may never see Thread 1's write, or may see writes in a different order.
HB rules (key ones)
- Program order — each action in a thread HB the next action in that thread.
- Monitor lock — unlock of a monitor HB every subsequent lock of that same monitor.
- volatile write — a write to a
volatilefield HB every subsequent read of that field. - Thread start —
Thread.start()HB any action in the started thread. - Thread join — all actions in thread T HB
T.join()returning. - Transitivity — if A HB B and B HB C then A HB C.
// Pattern: use a volatile flag to safely publish an initialised object
class DataPublisher {
private int value = 0; // not volatile
private volatile boolean ready = false; // volatile provides HB
// Thread 1
public void publish() {
value = 42; // write 1
ready = true; // volatile write — HB edge established
}
// Thread 2
public void consume() {
if (ready) { // volatile read
// Because volatile-write HB volatile-read, and
// program order gives write1 HB volatile-write,
// transitivity guarantees Thread 2 sees value == 42
System.out.println(value); // guaranteed: 42
}
}
}
When volatile is NOT enough HB only guarantees visibility — it does not make compound operations atomic.
import java.util.concurrent.atomic.AtomicInteger;
private volatile int count = 0;
// BROKEN — not atomic even with volatile
count++; // read + increment + write — two threads can interleave
// Correct
AtomicInteger counter = new AtomicInteger(0);
counter.incrementAndGet(); // single CAS operation
QA relevance: Selenium/Playwright shared driver instances, static test state, and @BeforeAll setup data all benefit from correct HB reasoning. A flaky test that only fails under parallel execution often has a missing HB edge.