Java final Visibility: JMM Freeze, This Escape, and Lock-Free Guarantees
This article explains how Java's final keyword ensures cross-thread visibility of final fields through the JMM's freeze action at constructor end, provided the this reference does not escape during construction, demonstrating with a code example that shows a race condition when this escapes and the correct behavior when final fields are properly frozen.
Introduction: final Beyond Immutability
Most developers know final as a modifier that makes variables assign-once, prevents method overriding, or blocks class inheritance. However, in the Java Memory Model (JMM), final has a crucial concurrency role: it guarantees visibility of final fields across threads without requiring volatile or locks — provided the this reference does not escape during construction.
What Is "This Escape"?
Escape means an object is passed to another thread before its constructor finishes. The article illustrates this with a runnable example on Windows 11 using Java 17.
Code Example: Demonstrating This Escape
public class ThisEscape {
static Holder holder;
static class Holder {
int x;
Holder() {
// this escapes here, before x is initialized
holder = this;
// Simulate remaining initialization work
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
// x assigned last
this.x = 42;
}
}
public static void main(String[] args) throws Exception {
Thread writer = new Thread(() -> new Holder());
Thread reader = new Thread(() -> {
while (holder == null) {
try { Thread.sleep(10); } catch (InterruptedException e) {}
}
System.out.println("during construction: x = " + holder.x);
});
writer.start();
reader.start();
writer.join();
reader.join();
System.out.println("after construction: x = " + holder.x);
}
}Execution Results
during construction: x = 0
after construction: x = 42
during construction: x = 0
after construction: x = 42
during construction: x = 0
after construction: x = 42Three runs produce identical output: during construction the reading thread sees x = 0 (the default int value), while after construction it sees x = 42.
Timeline Analysis
Constructor thread enters Holder(), first line executes holder = this — the partially initialized object reference is published.
Constructor sleeps for 1 second; initialization pauses.
Reader thread polls holder, finds it non-null, and immediately reads holder.x.
At this moment x is still 0 because this.x = 42 has not executed.
After 1 second, constructor resumes, assigns x = 42, and finishes.
Subsequent reads see 42.
The root cause: this escaped mid-construction, allowing another thread to observe a "half-initialized" object. This is called this escape .
JMM Freeze Action for final Fields
The JMM defines a freeze action for each final field. This action occurs at the end of the constructor that assigns the field. In the example, if x were declared final:
Constructor writes this.x = 42.
At the instant the constructor returns, JMM performs a freeze: the fact x = 42 is "sealed".
Thereafter, any thread that obtains a reference to the object and reads x is guaranteed to see 42 — never 0 or any intermediate value.
Critical precondition: this must not escape. Because freeze happens at constructor end, if this is handed out earlier, a reading thread can access the field before freeze occurs, seeing the default value.
Conclusion
The opening statement distills to: final provides cross-thread visibility for final fields without volatile or synchronization, contingent on this not escaping during construction. This is a foundational JMM guarantee that enables safe publication of immutable objects.
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.
samdeepthink
Knowledge Planet: Old Dock's Tech Chronicles Zhihu: SamDeepThinking A technical manager who still codes heavily on the front line. From junior developer to tech lead, then tech manager, now leading the whole front‑ and back‑end development team—leveling up along the way. I have some insights on programming, career development, and tech management.
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.
