Visibility and reordering
Why one thread can fail to see another thread's write (a stop flag that hangs forever, and the println that hides it), why operations appear reordered (a real two-thread litmus test), the three culprits behind both, and how the Java Memory Model turns them into a contract.
On this page
- Picture it first: the notebook and the office whiteboard
- Under the hood: the stop flag that never stops
- The accidental fix: println and sleep
- Reordering: the result that can't happen
- The three culprits, and the one contract
- Stopping a background worker: from naive to staff
- Real world
- Advanced: what really happens, and the traps around it
- How to say it in the interview
👀 What are visibility and reordering?
Visibility is whether one thread is guaranteed to see a value another thread wrote. Reordering is the compiler or CPU running your statements in a different order than you wrote them, as long as the thread doing the work can't tell. Single-threaded code never notices either one. Add a second thread and you get a loop that never stops even though running was set to false, or a result that "can't happen" showing up 3,088 times in 3 seconds.
For this lesson, we'll start the Java Memory Model topic from zero. You'll watch a real stop flag hang forever, see why a stray println "fixes" it, run the classic two-thread test that catches a CPU reordering your code, and meet the three culprits behind all of it. Interviewers love this one because the bug is three lines long, passes every unit test, and the answer "add volatile" is only the start: the follow-up "why?" is where people who memorised the keyword separate from people who understand the contract.
What you’ll learn
- Explain visibility and reordering in plain words, and why single-threaded code never notices either
- Reproduce the stop-flag hang and explain it as the JIT hoisting a field read out of a loop (it stops under
-Xint) - Explain why adding
printlnorThread.sleeponly hides the bug (JLS 17.3:sleephas no synchronization semantics) - Run the
x = 1; r1 = y/y = 1; r2 = xlitmus test and explainr1 == r2 == 0with store buffers - Name the three culprits (compiler/JIT, CPU, caches as a mental model only) and why coherent caches are not the cause
- Describe the Java Memory Model as a contract built on happens-before, and list the tools that create edges
- Stop a background worker the naive, solid and staff way: plain flag,
volatileflag, and **owner + volatile +interrupt()+join(timeout)** - Contrast x86 TSO with weaker ARM/POWER ordering, and explain what
volatilecosts and does not do
Premium lesson
Keep reading with the Java Pass
The rest of this lesson is part of Java One-Stop Interview Prep: in-depth explanations, diagrams, model answers and how to say them in the interview.
- Picture it first: the notebook and the office whiteboard
- Under the hood: the stop flag that never stops
- The accidental fix: println and sleep
- Reordering: the result that can't happen
- The three culprits, and the one contract
- Stopping a background worker: from naive to staff
- Real world
- Advanced: what really happens, and the traps around it
- How to say it in the interview
From ₹299 · one-time payment · No auto-renewal
Further reading (13)
- JLS (Java SE 21), Chapter 17: Threads and Locks: 17.3 sleep/yield have no synchronization semantics (hoisted-loop example), 17.4 memory model and happens-before, 17.7 non-atomic long/double
- JSR-133 (Java Memory Model) FAQ, Jeremy Manson and Brian Goetz: what reordering is, why the old model was broken, what volatile means since Java 5
- The Java Memory Model (Bill Pugh's JMM pages): history of the original model's flaws and JSR-133
- Aleksey Shipilev: Java Memory Model Pragmatics: access atomicity, word tearing, litmus tests, how HotSpot implements the JMM
- Aleksey Shipilev: Close Encounters of The Java Memory Model Kind: common misconceptions, including the 'caches' explanation and hoisted loops
- Doug Lea: Using JDK 9 Memory Order Modes: plain, opaque, release/acquire and volatile modes in VarHandle
- OpenJDK jcstress: the harness OpenJDK uses to run litmus tests like the one in this lesson
- Jeff Preshing: Memory Reordering Caught in the Act (2012): the same store-load litmus test caught on an Intel x86 CPU, fixed with mfence
- Sewell et al.: x86-TSO, a rigorous and usable programmer's model for x86 multiprocessors (CACM 2010): store buffers and why x86 allows only store-load reordering
- TSOEnabler (Saagar Jha): documents Apple silicon's hardware TSO mode used by Rosetta 2 for translated x86 processes
- Java Concurrency in Practice (Goetz et al., 2006), chapter 3 (Sharing Objects) and chapter 16 (The Java Memory Model): visibility, the NoVisibility example, happens-before
- The Java Memory Model Explained: Happens-Before and Concurrency Semantics (Java Code Geeks, 2026): overview of the JMM and happens-before
- AWS Graviton Getting Started: context for moving Java workloads from x86 to ARM servers