Java Happens‑Before Explained: Volatile, Synchronized & Instruction Reordering
This article explains Java’s happens‑before guarantees, covering instruction reordering, the visibility guarantees of volatile variables and synchronized blocks, and demonstrates how improper reordering can cause stale data or wasted resources through detailed code examples such as FrameExchanger and ValueExchanger.
Instruction Reordering
Modern CPUs can execute independent instructions in parallel. For example, the two statements below have no data dependency and can be executed concurrently:
a = b + c;
d = e + f;Conversely, the following statements cannot be reordered because the second depends on the result of the first:
a = b + c;
d = a + e;When these statements are part of a larger block, the CPU may reorder them to increase parallelism, as shown:
a = b + c;
d = a + e;
l = m + n;
y = x + z;Reordering can improve performance by allowing more instructions to run simultaneously.
Reordering Problems in Multi‑CPU Computers
Reordering can cause subtle bugs in multithreaded programs. The example below illustrates a frame‑exchanging scenario where two threads cooperate to generate and render frames.
public class FrameExchanger {
private long framesStoredCount = 0;
private long framesTakenCount = 0;
private boolean hasNewFrame = false;
private Frame frame = null;
// called by the producer thread
public void storeFrame(Frame frame) {
this.frame = frame;
this.framesStoredCount++;
this.hasNewFrame = true;
}
// called by the consumer thread
public Frame takeFrame() {
while (!hasNewFrame) {
// busy‑wait until a new frame arrives
}
Frame newFrame = this.frame;
this.framesTakenCount++;
this.hasNewFrame = false;
return newFrame;
}
}If the three statements in storeFrame are reordered so that hasNewFrame is set to true before frame is assigned, the consumer may read a stale frame, wasting CPU/GPU resources.
Java volatile Visibility Guarantee
The volatile keyword ensures that writes to a volatile variable are immediately flushed to main memory and reads always fetch the latest value from main memory, providing a visibility guarantee.
Volatile Write Visibility Guarantee
When a volatile variable is written, the write is performed directly to main memory, and all other variables visible to the writing thread are also flushed.
this.nonVolatileVarA = 34;
this.nonVolatileVarB = new String("Text");
this.volatileVarC = 300;Because the volatile write occurs after the non‑volatile writes, the non‑volatile values are also synchronized to main memory.
Volatile Read Visibility Guarantee
When a volatile variable is read, the read is performed directly from main memory, and all other variables visible to the reading thread are also refreshed.
c = other.volatileVarC;
b = other.nonVolatileB;
a = other.nonVolatileA;The read of volatileVarC forces a refresh of nonVolatileB and nonVolatileA from main memory.
Java Volatile Happens‑Before Guarantee
Declaring hasNewFrame as volatile in FrameExchanger adds ordering constraints:
public class FrameExchanger {
private long framesStoredCount = 0;
private long framesTakenCount = 0;
private volatile boolean hasNewFrame = false;
private Frame frame = null;
public void storeFrame(Frame frame) {
this.frame = frame;
this.framesStoredCount++;
this.hasNewFrame = true; // volatile write
}
public Frame takeFrame() {
while (!hasNewFrame) {
// busy‑wait
}
Frame newFrame = this.frame;
this.framesTakenCount++;
this.hasNewFrame = false;
return newFrame;
}
}If the JVM reordered the statements so that hasNewFrame is set before frame, the consumer could exit the loop and read an old frame.
Volatile Write Happens‑Before
All instructions that occur before a volatile write are guaranteed to happen before that write.
public void storeFrame(Frame frame) {
this.frame = frame;
this.framesStoredCount++;
this.hasNewFrame = true; // volatile write
}The JVM may reorder the first two statements, but it cannot move them after the volatile write.
Volatile Read Happens‑Before
All instructions that occur after a volatile read are guaranteed to happen after that read.
int a = this.volatileVarA; // volatile read
int b = this.nonVolatileVarB;
int c = this.nonVolatileVarC;The reads of nonVolatileVarB and nonVolatileVarC must remain after the volatile read.
Java Synchronized Visibility Guarantee
Synchronized blocks provide visibility guarantees similar to volatile.
Synchronized Entry Guarantee
When a thread enters a synchronized block, all variables visible to the thread are refreshed from main memory.
Synchronized Exit Guarantee
When a thread exits a synchronized block, all modified variables are flushed back to main memory.
Synchronized Visibility Example
public class ValueExchanger {
private int valA;
private int valB;
private int valC;
public void set(Values v) {
this.valA = v.valA;
this.valB = v.valB;
synchronized(this) {
this.valC = v.valC;
}
}
public void get(Values v) {
synchronized(this) {
v.valC = this.valC;
}
v.valB = this.valB;
v.valA = this.valA;
}
}Placing the synchronized block at the end of set ensures all updates are flushed after the method returns, while placing it at the beginning of get guarantees the reads see the latest values.
Java Synchronized Happens‑Before Guarantee
Synchronized blocks provide two happens‑before guarantees: one at the block’s start and one at its end.
Block‑Start Guarantee
All reads inside the block see values refreshed from main memory, so no read may be reordered before the block.
public void get(Values v) {
synchronized(this) {
v.valC = this.valC;
}
v.valB = this.valB;
v.valA = this.valA;
}Block‑End Guarantee
All writes performed before exiting the block are flushed to main memory, preventing writes from being reordered after the block.
public void set(Values v) {
this.valA = v.valA;
this.valB = v.valB;
synchronized(this) {
this.valC = v.valC;
}
}If the synchronized block were moved before the writes, the writes could occur after the block’s exit, breaking the visibility guarantee.
Cognitive Technology Team
Cognitive Technology Team regularly delivers the latest IT news, original content, programming tutorials and experience sharing, with daily perks awaiting you.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
