The <code>volatile</code> Keyword in Java

volatile guarantees that reads and writes of a field go to main memory, not a CPU register or cache. Writes are immediately visible to other threads; reads always fetch the latest value. It does not make compound operations (x++) atomic.

What volatile fixes

class Worker implements Runnable {
    private boolean stopped;              // ❌ NOT volatile
    public void run() {
        while (!stopped) { doWork(); }    // might loop forever β€” cached value
    }
    public void stop() { stopped = true; }
}

Without volatile, the JVM is free to cache stopped in a register inside run(). The stop flag set from another thread may never be seen.

private volatile boolean stopped;         // βœ… every read sees the latest write

What volatile does not fix

private volatile int counter;

public void increment() {
    counter++;                             // read + add + write β€” THREE operations
}

Two threads calling increment can interleave and lose updates. For atomicity, use AtomicInteger (or LongAdder for high-contention counters).

When to use it

  • Stop/ready flags read by one thread, written by another.
  • Publishing an immutable object reference after safe construction (double-checked locking idiom).
  • Configuration that changes rarely and is read often.

Double-checked locking

private volatile Instance instance;

public Instance get() {
    Instance local = instance;
    if (local == null) {
        synchronized (this) {
            local = instance;
            if (local == null) instance = local = new Instance();
        }
    }
    return local;
}

The volatile is essential β€” without it, another thread could see a non-null reference pointing to a half-constructed Instance.

volatile vs synchronized vs Atomic*

VisibilityAtomicityLock overhead
volatileYesNo (single read/write only)Very low
synchronizedYesYes β€” whole critical sectionMedium (lock acquisition)
AtomicIntegerYesYes β€” for single-word ops (CAS)Low

Common mistakes

  • Expecting atomicity β€” volatile only helps visibility. For read-modify-write, use AtomicInteger or a lock.
  • Using volatile on a reference to a mutable object β€” the reference is visible, but the object's fields are still subject to races.
  • Using volatile instead of synchronized for protecting related fields β€” only individual reads/writes are synchronised, not groups.

Related

Pillar: Java keywords. See also synchronized.