Unravel โบ Java concepts โบ Concurrency
Visibility and the Java Memory Model
Without synchronisation one thread may never see another thread's writes, or may see them in a surprising order.
Learn these first
At a glance
Two colleagues each keep a private notebook copy of the shared whiteboard to work faster.
- 1A plain field written by thread A may stay in a CPU cache or register: thread B can loop forever on while (!stop) even after A set stop = trueDeclaring volatile boolean stop fixes the visibility.
- 2volatile guarantees visibility and ordering of that variable, but not atomicity of compound actions: volatile int count; count++ is read, add, write, three steps, and can lose updatesUse AtomicInteger or a lock.
- 3synchronized and Lock give both mutual exclusion and visibility: everything written before releasing the lock is visible to the next thread that acquires it
- 4Safe publication: an object is safely shared when it is stored in a volatile or final field, a synchronized block, or a concurrent collection
- Double-checked locking for lazy singletons only works when the field is volatile: otherwise another thread may see a non-null reference to a half-constructed object
- The compiler and CPU may reorder independent instructions; the memory model defines which reorderings are allowed
- The JVM emits memory barriers around volatile accesses (a store-load fence after a volatile write on x86)
public class Stopper { private volatile boolean running = true; private int processed; public void run() { while (running) { synchronized (this) { processed++; } } } public void stop() { running = false; }}class Lazy { private static volatile Lazy instance; static Lazy get() { if (instance == null) { synchronized (Lazy.class) { if (instance == null) instance = new Lazy(); } } return instance; }}Read the full explanation (about 2 min)
Without synchronisation one thread may never see another thread's writes, or may see them in a surprising order. volatile, synchronized, locks and atomics create "happens-before" guarantees that make writes visible.
A mental model
Two colleagues each keep a private notebook copy of the shared whiteboard to work faster. Without a rule for when to copy back, one keeps reading an outdated copy. volatile means "always read and write the whiteboard itself".
How it works
A plain field written by thread A may stay in a CPU cache or register: thread B can loop forever on while (!stop) even after A set stop = true. Declaring volatile boolean stop fixes the visibility.
volatile guarantees visibility and ordering of that variable, but not atomicity of compound actions: volatile int count; count++ is read, add, write, three steps, and can lose updates. Use AtomicInteger or a lock.
synchronized and Lock give both mutual exclusion and visibility: everything written before releasing the lock is visible to the next thread that acquires it.
Safe publication: an object is safely shared when it is stored in a volatile or final field, a synchronized block, or a concurrent collection.
Going deeper
Double-checked locking for lazy singletons only works when the field is volatile: otherwise another thread may see a non-null reference to a half-constructed object.
The compiler and CPU may reorder independent instructions; the memory model defines which reorderings are allowed. Reasoning "it worked in my test" does not work, because races are timing dependent.
The simplest correct strategy: avoid shared mutable state (immutable objects, thread confinement, message passing), and when you must share, use the high-level classes from java.util.concurrent.
Under the hood
The JVM emits memory barriers around volatile accesses (a store-load fence after a volatile write on x86). The Java Memory Model (JSR-133) defines happens-before edges for monitor unlock/lock, volatile write/read, thread start/join and final field freeze.
Common mistakes
- Using
volatilefor a counter. - A stop flag that is not volatile.
- Double-checked locking without volatile.
- Assuming the order of writes is the order other threads see.
Part of a learning path
- Concurrency beyond the basics ยท previous: Timers and scheduled executors ยท next: Race conditions and deadlocks
Related concepts
Frequently asked questions
What is Visibility and the Java Memory Model?
Without synchronisation one thread may never see another thread's writes, or may see them in a surprising order. volatile, synchronized, locks and atomics create "happens-before" guarantees that make writes visible.
What are the most common mistakes with Visibility and the Java Memory Model?
Using volatile for a counter. A stop flag that is not volatile. Double-checked locking without volatile. Assuming the order of writes is the order other threads see.
How can I see Visibility and the Java Memory Model in real code?
Paste your own Java into Unravel and it will point out where visibility and the java memory model appears, explain how it works at the detail level you choose, and draw the flow of the code around it.