The Java Memory Model (JMM) defines how threads interact with memory and establishes the rules for reading and writing shared variables in a multithreaded environment. It ensures that changes made by one thread become visible to other threads in a predictable and consistent manner.
Key Points: • JMM defines how data is shared between threads. • It guarantees memory visibility, ordering, and atomicity rules. • Without JMM, different threads could see different values of the same variable. • JMM provides the foundation for synchronization, volatile, and concurrent programming. • It helps prevent unpredictable behavior in multithreaded applications.
Why Do We Need the Java Memory Model?
Modern computers use:
• CPU Registers • CPU Caches • Main Memory (RAM)
For performance reasons, threads may work with cached copies of variables instead of reading directly from main memory.
Problem:
Thread 1 updates a variable.
Thread 2 may continue reading an outdated cached value.
Result:
Inconsistent application behavior.
The Java Memory Model defines rules that ensure threads see data correctly.
How JMM Is Linked to Threads
Each thread has its own working memory where copies of variables may be stored.
Structure:
Main Memory | --------------------- | | | Thread A Thread B Thread C Working Working Working Memory Memory Memory
When a thread updates a shared variable:
• The change may initially exist only in its working memory. • Other threads may not immediately see the update.
JMM defines how and when these changes become visible.
Three Important Concepts of JMM
1. Visibility
Visibility ensures that changes made by one thread are visible to other threads.
Example:
Thread 1:
flag = true;
Thread 2:
while (!flag) {
}Without proper synchronization:
Thread 2 may never see the updated value.
Solution:
Use volatile or synchronization.
Example:
private volatile boolean flag =
false;Now all threads see the latest value.
2. Atomicity
Atomicity means an operation is performed completely or not at all.
Example:
count++;
This is not atomic.
Internally:
1. Read count 2. Increment value 3. Write count
Multiple threads can interfere between these steps.
Solution:
• synchronized • AtomicInteger
3. Ordering
The JVM and CPU may reorder instructions for optimization.
Example:
x = 10;
flag = true;The JVM may internally reorder instructions.
Without proper memory guarantees:
Another thread may see:
flag = true
before
x = 10
JMM prevents harmful reordering using:
• volatile • synchronized • locks
The Happens-Before Relationship
One of the most important concepts in JMM is Happens-Before.
It guarantees:
If Action A happens-before Action B,
then the effects of A are visible to B.
Examples:
• Unlock happens-before subsequent lock. • Volatile write happens-before volatile read. • Thread start happens-before thread execution. • Thread completion happens-before join() returns.
Role of volatile in JMM
volatile ensures:
• Visibility • Ordering
Example:
private volatile boolean running =
true;If one thread changes:
running = false;
Other threads immediately observe the update.
Important:
volatile does not provide atomicity.
Role of synchronized in JMM
synchronized provides:
• Visibility • Atomicity • Ordering
Example:
public synchronized void update() {
value++;
}Benefits:
• Changes are flushed to main memory. • Other threads see updated values. • Critical sections are protected.
Example: Suppose a banking application has a shared account balance.
Thread 1:
Deposits money.
Thread 2:
Checks balance.
Without JMM guarantees:
Thread 2 may see stale data.
With synchronization:
Thread 2 always sees the latest balance.
Code Example:
class SharedData {
private volatile boolean ready =
false;
public void setReady() {
ready = true;
}
public boolean isReady() {
return ready;
}
}
public class Demo {
public static void main(String[] args) {
SharedData data =
new SharedData();
Thread writer =
new Thread(() -> {
data.setReady();
});
Thread reader =
new Thread(() -> {
while (!data.isReady()) {
}
System.out.println(
"Data Available");
});
writer.start();
reader.start();
}
}Output:
Data Available
Without volatile, the reader thread might not observe the update immediately.
Real-World Example
Consider a web server.
Thread 1:
Updates application configuration.
Thread 2:
Reads configuration values.
The Java Memory Model ensures:
• Updated configuration becomes visible. • Threads observe a consistent state. • Data corruption is avoided.
Benefits of JMM
• Consistent memory visibility • Safe thread communication • Predictable multithreaded behavior • Reduced concurrency bugs • Foundation for Java synchronization mechanisms
Interview Tip: A concise interview answer is:
"The Java Memory Model (JMM) defines how threads interact with shared memory and establishes rules for visibility, atomicity, and ordering of operations. It ensures that changes made by one thread become visible to other threads in a predictable manner. Features such as synchronized, volatile, and locks rely on the JMM to provide safe communication between threads."