volatile keyword in Java is a field modifier that dictates how the Java Virtual Machine (JVM) and the underlying hardware handle memory visibility and instruction ordering for a specific variable. It guarantees that any thread reading a volatile field will always see the most recently written value, effectively disabling thread-local caching for that variable.
The Java Memory Model (JMM) Semantics
The behavior ofvolatile is strictly defined by the Java Memory Model, which provides two primary guarantees:
1. Visibility Guarantee
In a multi-threaded environment, threads typically cache variables in CPU registers or local cache tiers (L1/L2/L3) to optimize performance. This can lead to cache coherence issues where one thread updates a variable, but other threads continue to read stale data from their local caches. Declaring a field asvolatile instructs the JVM to bypass these local caches. Every write to a volatile field is immediately flushed to main memory, and every read of a volatile field is fetched directly from main memory.
2. Ordering Guarantee (Happens-Before Relationship)
Compilers, the JVM, and CPUs frequently reorder instructions to optimize execution pipelines. The JMM restricts this reordering aroundvolatile fields by establishing a strict happens-before relationship:
- A write to a
volatilefield happens-before every subsequent read of that same field. - Memory Barriers: To enforce this, the JVM inserts hardware-level memory barriers (fences).
- A
StoreStoreandLoadStorebarrier prevents operations before thevolatilewrite from being reordered after it. - A
StoreLoadbarrier ensures thevolatilewrite is visible before any subsequent reads. - A
LoadLoadandLoadStorebarrier prevents operations after thevolatileread from being reordered before it.
- A
volatile variable, all variables (even non-volatile ones) updated by that thread prior to the write become visible to any other thread that subsequently reads the volatile variable.
Atomicity Constraints
A critical distinction in Java is thatvolatile ensures visibility and ordering, but it does not guarantee atomicity for compound operations.
- Primitive Reads/Writes: Reads and writes to a
volatilefield are atomic. This includes 64-bit primitives (longanddouble). Withoutvolatile, the JMM permits 64-bit reads and writes to be treated as non-atomic 64-bit operations (JLS 17.7). The JVM may execute them as two separate 32-bit operations, which can result in “half-writes” (reading a partially updated value where 32 bits belong to one write and 32 bits belong to another). Declaring the field asvolatileenforces atomic reads and writes of the entire 64-bit value, preventing half-writes. - Compound Operations: Operations that require a read-modify-write sequence are not atomic, even if the field is
volatile.
volatile does not acquire monitors or locks, it cannot provide mutual exclusion. If multiple threads are concurrently writing to a field based on its current state, volatile is insufficient, and synchronization mechanisms (like synchronized blocks or java.util.concurrent.atomic classes) must be used instead.
Tired of Poor Java Skills? Fix That With Deep Grasping!Learn More





