Skip to content

JDD 2022: Maciej Przepióra - Java memory model for mere mortals

Maciej Przepióra

CommunityPROIDEA Events40 minBeginnerOpen on YouTube ↗

Engineers explore architecture and security mechanisms for JDD 2022: Maciej Przepióra - Java memory model for mere mortals.

Summary

### Overview In this talk from JDD 2022, Maciej Przepióra explores the Java Memory Model (JMM) and how ModernHardware and runtime optimizations affect concurrent execution. While Java developers are generally shielded from low-level execution details by the Java Virtual Machine (JVM) and the standard library, understanding memory visibility and instruction reordering is crucial when building concurrent libraries or optimizing high-performance applications.

### Key Topics - **Instruction Reordering:** Compilers, Just-In-Time (JIT) compilers, and CPU pipelines reorder execution steps and memory writes to optimize speed, bounded by the "as-if-serial" semantics in single-threaded environments. - **Cache Coherence Protocols:** Multi-core hardware employs snooping on the bus and protocols such as MESI (Modified, Exclusive, Shared, Invalid) to coordinate state between processor caches and main memory. - **Limitations of `volatile`:** While `volatile` ensures immediate visibility across threads by preventing cached CPU register values from remaining stale, it does not solve race conditions requiring atomic compound operations like compare-and-swap (CAS). - **The Java Memory Model & Happens-Before:** Introduced in its modern form in Java 5, the JMM establishes a partial ordering relation (`happens-before`) across program actions to define formal visibility and ordering guarantees.

### Technical Details Przepióra walks through a classic concurrent example featuring four shared variables (`x`, `y`, `a`, `b`) across two threads to illustrate how instruction reordering and stale memory reads can yield surprising outcomes, including scenarios where both variables evaluate to `0`. Under single-threaded constraints, the JVM guarantees "as-if-serial" semantics, ensuring optimizations do not alter program outcomes. However, in concurrent environments lacking synchronization, compilers and processors can freely reorder independent assignments.

At the hardware layer, processors enforce cache coherence using protocols such as MESI (Modified, Exclusive, Shared, Invalid) or proprietary vendor adaptations by Intel and AMD. Even with coherent caches, processor registers and memory write buffers can still obscure updates across cores. Rather than requiring developers to manually insert platform-specific memory barriers or memory fences (as in C/C++), the JVM automatically places these instructions based on standard synchronization primitives.

The talk defines specific `happens-before` rules governing thread visibility: - **Program Order Rule:** Each action within a single thread happens before subsequent actions in that thread. - **Monitor Lock Rule:** An unlock operation on a monitor happens before every subsequent lock on that same monitor (applying to both implicit monitors and `java.util.concurrent` locks). - **Volatile Variable Rule:** A write to a volatile field happens before subsequent reads of that same field (with atomic variables sharing volatile semantics). - **Thread Management Rules:** A call to `Thread.start()` happens before any action in the started thread, and all actions in a thread happen before another thread detects its termination. - **Interruption and Finalizer Rules:** An interrupt call happens before the target thread detects it, and object constructor completion happens before its `finalize()` method execution starts. - **Transitivity:** If action *A* happens before *B*, and *B* happens before *C*, then *A* happens before *C*.

### Takeaways While the underlying mechanics of memory barriers, cache lines, and MESI states are complex, standard Java developers rarely need to manually construct complex low-level synchronization. The JDK provides battle-tested abstractions—such as thread-safe collections and utilities in `java.util.concurrent`—that natively supply transitive happens-before guarantees. Przepióra recommends Brian Goetz's *Java Concurrency in Practice* for mastering concurrency principles, emphasizing that the core memory model fundamentals established in Java 5 remain the foundation of Java concurrency today.

Related talks