Java Memory Model and Happens-Before
Fast recall
Quick revision
Core answer
Ability to reason about visibility and ordering guarantees without relying on vague intuitions about 'memory flushing'.
Assuming that executing on a modern x86 CPU gives you sequentially consistent behaviour. JMM allows reorderings that can break code not properly synchronized.
Enumerate the specific happens-before rules (monitor unlock→lock, volatile write→read, thread start, thread join) and explain how they chain transitively.
Interview-ready guide
Interview answer
The Java Memory Model defines when a write by one thread becomes visible to another — without it, compilers and CPUs are free to reorder operations in ways that break multithreaded code.
Happens-before:
- If A happens-before B, then A's writes are guaranteed visible to B
- Synchronized unlock happens-before the next lock on the same monitor
- Volatile write happens-before any subsequent volatile read of the same variable — and covers all prior writes by that thread (transitivity)
Practical trap:
- x86 has a strong memory model — violations are masked; code that works on x86 can fail on ARM due to its weaker ordering
- The JMM is the contract you program to, not the hardware behavior you happen to observe
Final fields:
- Safe without synchronization if the object is properly constructed (
thisreference doesn't escape the constructor) - This is why immutable objects are inherently thread-safe
Volatile piggyback pattern:
- Write non-volatile state before writing a volatile flag — all prior writes become visible to any thread that reads the flag
I recommend thinking about happens-before edges explicitly when designing concurrent code. The volatile piggyback pattern is one of the most useful applications of transitivity.
Java Memory Model and Happens-Before
Direct Answer
The JMM defines when writes by one thread are guaranteed to be visible to reads by another. A happens-before (HB) relationship means all writes before the HB edge are visible to all reads after it. Without HB, the compiler and CPU are free to reorder instructions and cache writes in registers.
Deep Dive & Architecture
They're related but distinct.
A data race is a memory-level bug: two threads access the same memory location, at least one writes, and there's no happens-before ordering between them.
The JMM says the behavior is undefined — you can see stale values, torn reads, or impossible states. A race condition is a logical-level bug: the correctness of your program depends on an accidental interleaving of operations. You can have a race condition WITHOUT a data race (all accesses are synchronized, but the logic is still wrong) and a data race WITHOUT a race condition (benign racy read, though the JMM says it's still undefined behavior).
Thinking the JMM is about 'heap vs stack' memory — that's JVM memory layout, NOT the JMM. Missing that happens-before, not 'memory flushing', is the formal guarantee
Common Mistakes & Pitfalls
Assuming that executing on a modern x86 CPU gives you sequentially consistent behaviour. JMM allows reorderings that can break code not properly synchronized.
Check your understanding
Answer these without looking back at the article.
- What is the Java Memory Model (JMM)? Why does it exist and what guarantees does it provide?
- What does the volatile keyword guarantee in Java, and when is it sufficient — and when is it not?
- What's the difference between `volatile` and `AtomicInteger`/`AtomicLong` in Java? When is each the right choice?
Related interview prep categories
2Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.