Java Memory Model (JMM) – In-Depth Summary
The Java Memory Model (JMM) defines how threads in a Java program interact through
memory, specifying rules for visibility, ordering, and atomicity of shared variables in a
multithreaded environment. It ensures consistent and predictable behavior of concurrent
Java programs, especially when multiple threads read and write shared data.
🔍 Why the Java Memory Model Matters
In multithreaded programs, threads often share variables. Without proper
synchronization, threads may see inconsistent or stale values due to:
● CPU caches
● Compiler optimizations
● Instruction reordering
JMM specifies how and when changes made by one thread become visible to others,
preventing subtle bugs caused by race conditions or memory inconsistencies.
🧩 Key Concepts in JMM
1. Main Memory and Working Memory
○ Every thread has its own working memory (a local copy of variables).
○ The main memory holds the “true” values of variables shared by all
threads.
○ Threads read variables from and write variables back to main memory, but
may keep local cached copies.
2. Happens-Before Relationship
○ Defines the order of operations such that if one action happens-before
another, then the first is visible and ordered before the second.
○ Examples include:
■ Program order rule: Statements in a single thread happen in order.
■ Monitor lock rule: Unlocking a monitor happens-before locking it
again.
■ Volatile variable rule: A write to a volatile variable happens-before
any subsequent read of that variable.
3. Volatile Variables
○ Declared with volatile keyword.
○ Guarantees visibility: writes to volatile variables are immediately visible to
other threads.
○ Prevents instruction reordering involving volatile variables.
4. Atomicity and Synchronization
○ Atomic operations are indivisible (e.g., reads/writes of int variables are
atomic).
○ Synchronization (using synchronized blocks or methods) provides
mutual exclusion and establishes happens-before edges, ensuring visibility
and ordering.
🧠 Memory Visibility Problems
Without proper synchronization:
● One thread may update a variable, but others might still see the old value.
● Threads may observe operations in a different order than written, causing
inconsistent program states.
⚙️ Synchronization Mechanisms
● Synchronized blocks/methods:
Enforce mutual exclusion and memory visibility. When a thread exits a
synchronized block, changes are flushed to main memory; when entering,
variables are reloaded.
● Volatile variables:
Lightweight visibility guarantees without locking but no mutual exclusion.
● Atomic variables (java.util.concurrent.atomic):
Provide atomic read-modify-write operations.
📚 JMM in Practice: Example
java
CopyEdit
class SharedData {
private volatile boolean flag = false;
public void writer() {
flag = true; // write to volatile
public void reader() {
if (flag) { // read volatile
// guaranteed to see updates before this read
}
Here, the flag variable’s volatile modifier ensures that changes made by one thread in
writer() are visible to other threads in reader().
🧠 Summary
● JMM defines rules for how threads interact via memory in Java.
● It addresses visibility, ordering, and atomicity issues in concurrent programming.
● Key tools: volatile variables, synchronized blocks, and atomic classes.
● Understanding JMM is essential to write correct and efficient multithreaded Java
code.