Fundamentals 9 min read

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.

Programmer DD
Programmer DD
Programmer DD
Unlocking Java’s Happens‑Before: When Do Thread Changes Become Visible?

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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Javaconcurrencythread safetyMemory ModelHappens-before
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.