volatile — Visibility Guarantee in Java
Fast recall
Quick revision
Core answer
Understanding of the Java Memory Model (JMM) and the distinction between visibility and atomicity.
Believing volatile makes all operations on a variable thread-safe. It does not — volatile int counter++ is still a non-atomic read-modify-write.
Explain the happens-before relationship that volatile establishes and why it is sufficient for a single-writer / multiple-reader flag pattern.
Interview-ready guide
Interview answer
volatile guarantees visibility — every read sees the most recent write — but it does not guarantee atomicity.
What volatile does:
- Every write flushes to main memory; every read fetches from main memory — no stale cached values
- Volatile write acts as a memory fence: all preceding writes become visible after any volatile read of that variable
What volatile doesn't do:
count++on a volatileintis still broken — three steps (read, increment, write) that two threads can interleave- Use
AtomicIntegerfor read-modify-write operations
Where volatile is sufficient:
- Single-writer patterns: one thread sets a shutdown flag, all others read it
- Double-checked locking: without
volatileon the instance field, the constructor can be reordered — another thread sees a non-null but partially constructed object
I recommend volatile only for simple flags and the double-checked locking pattern. If you need compound operations on the value, you need AtomicInteger or synchronized.
volatile — Visibility Guarantee in Java
Direct Answer
volatile guarantees that reads and writes to a variable are always performed against main memory rather than a CPU cache or register, ensuring visibility across threads. It also prevents instruction reordering around the volatile access. It does not provide atomicity for compound operations like check-then-act, so it cannot replace synchronization for multi-step critical sections.
Deep Dive & Architecture
They're related but distinct.
A data race is a memory-level bug: two threads access the same memory location, at least one writes, and there's no happens-before ordering between them.
The JMM says the behavior is undefined — you can see stale values, torn reads, or impossible states. A race condition is a logical-level bug: the correctness of your program depends on an accidental interleaving of operations. You can have a race condition WITHOUT a data race (all accesses are synchronized, but the logic is still wrong) and a data race WITHOUT a race condition (benign racy read, though the JMM says it's still undefined behavior).
Thinking the JMM is about 'heap vs stack' memory — that's JVM memory layout, NOT the JMM. Missing that happens-before, not 'memory flushing', is the formal guarantee
Common Mistakes & Pitfalls
Believing volatile makes all operations on a variable thread-safe. It does not — volatile int counter++ is still a non-atomic read-modify-write.
Check your understanding
Answer these without looking back at the article.
- What is the Java Memory Model (JMM)? Why does it exist and what guarantees does it provide?
- What is the Java Memory Model (JMM) and what does the happens-before guarantee mean in practice?
- What's the difference between `volatile` and `AtomicInteger`/`AtomicLong` in Java? When is each the right choice?
Related interview prep categories
2Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.