Fundamentals 21 min read

Understanding Java Memory Model, Volatile, Atomicity, Visibility, and Ordering

This article explains the Java memory model, how variables are stored in main and working memory, and why concurrency issues like dirty reads, non‑atomic operations, and instruction reordering occur, while detailing the roles of volatile, synchronized, locks, and atomic classes in ensuring visibility, ordering, and atomicity.

Architect
Architect
Architect
Understanding Java Memory Model, Volatile, Atomicity, Visibility, and Ordering

The Java Memory Model (JMM) specifies that all variables reside in main memory and each thread has its own working memory, requiring reads and writes to go through these caches, which can cause visibility and ordering problems in multithreaded programs.

Examples illustrate dirty reads, non‑atomic increments, and instruction reordering, showing why the volatile keyword alone cannot guarantee atomicity.

Three core concepts of concurrent programming—atomicity, visibility, and ordering—are defined, with Java guaranteeing atomicity only for simple reads/writes of primitive types, while synchronized, Lock, and atomic classes provide stronger guarantees.

The volatile keyword ensures that writes are immediately visible to other threads and prevents certain reordering, but it does not make compound actions atomic; proper use cases and limitations are discussed.

Implementation details of volatile are described, including memory barriers, cache invalidation, and how the JVM emits lock‑prefix instructions to enforce ordering.

Typical scenarios such as status flags, thread termination, and double‑checked locking in singleton patterns are presented, with code examples wrapped in ... blocks.

Code snippets demonstrate the problems and solutions:

i = 10++;
x = 10; // statement 1
 y = x; // statement 2
 x++; // statement 3
 x = x + 1; // statement 4
i = 9;
// Thread 1
int i = 0;
while(!stop){
    doSomething();
}
// Thread 2
stop = true;
// Example with volatile flag
volatile boolean flag = false;
while(!flag){
    doSomething();
}
// In another thread
flag = true;
class Singleton {
    private volatile static Singleton instance = null;
    private Singleton() {}
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
public class Test {
    public volatile int inc = 0;
    public void increase() { inc++; }
    public static void main(String[] args) {
        final Test test = new Test();
        for (int i = 0; i < 10; i++) {
            new Thread(){
                public void run() {
                    for (int j = 0; j < 1000; j++) test.increase();
                }
            }.start();
        }
        while (Thread.activeCount() > 1) Thread.yield();
        System.out.println(test.inc);
    }
}
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.

JavaconcurrencyorderingvolatileMemory Modelatomicityvisibility
Architect
Written by

Architect

Professional architect sharing high‑quality architecture insights. Topics include high‑availability, high‑performance, high‑stability architectures, big data, machine learning, Java, system and distributed architecture, AI, and practical large‑scale architecture case studies. Open to ideas‑driven architects who enjoy sharing and learning.

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.