Unlocking Java’s Happens‑Before: When Do Thread Changes Become Visible?
The article explains the Java Memory Model’s happens‑before principle, detailing its eight core rules, how they ensure visibility and ordering across threads, provides code examples, analyzes a non‑thread‑safe snippet, and shows how to achieve safety using locks or volatile variables.
Building on a previous discussion of volatile , this article examines the Java Memory Model (JMM) concept of happens‑before , which guarantees that the result of one operation becomes visible to another when a happens‑before relationship exists between them.
Core Happens‑Before Rules
Program Order Rule: Within a single thread, actions written earlier in the code happen‑before those written later.
Lock Rule: An unlock on a monitor happens‑before every subsequent lock on the same monitor.
Volatile Variable Rule: A write to a volatile variable happens‑before every subsequent read of that same variable.
Transitivity Rule: If A happens‑before B and B happens‑before C, then A happens‑before C.
Thread Start Rule: The call to Thread.start() happens‑before any action in the newly started thread.
Thread Interrupt Rule: An invocation of Thread.interrupt() happens‑before the interrupted thread detects the interrupt.
Thread Termination Rule: All actions in a thread happen‑before another thread detects its termination via Thread.join() or Thread.isAlive().
Finalizer Rule: Object construction happens‑before its finalize() method execution.
Derived Happens‑Before Relationships
Placing an element into a thread‑safe queue happens‑before taking that element out.
Putting an element into a thread‑safe container happens‑before removing it.
Counting down on a CountDownLatch happens‑before a thread returns from await().
Releasing a Semaphore permit happens‑before acquiring that permit.
All actions of a task represented by a Future happen‑before calling Future.get().
Submitting a Runnable or Callable to an Executor happens‑before the task begins execution.
Practical Example and Analysis
int i = 0;
public void write(int j) { i = j; }
public int read() { return i; }Assume thread A calls write() before thread B calls read(). The article walks through the eight core rules and shows that none of them apply to this code: there is no program‑order relationship across threads, no lock, the field is not volatile, and no transitive link exists. Consequently, the happens‑before guarantee cannot be established and the program is not thread‑safe; the value read by thread B is undefined.
To make the snippet safe, one can either synchronize the methods (satisfying the lock rule) or declare i as volatile (satisfying the volatile rule), thereby establishing a happens‑before relationship.
Why Happens‑Before Matters
The happens‑before principle is a cornerstone of the JMM, used to reason about data races and thread safety in concurrent Java programs.
The following diagram (from "Java Concurrency in Practice") illustrates the relationship between happens‑before and the broader JMM.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
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.
