volatile

Visibility Problem

Each CPU core can cache variables. Without a rule that forces a fresh read, a thread may keep using an old cached value forever. The JIT may even hoist the read out of a loop. volatile guarantees that every read sees the latest write from any thread (a happens-before relation).

  • volatile gives visibility and ordering, but not atomicity: volatile int count; count++ is still a race.
  • Use it for flags and published references: volatile boolean running, double-checked locking singleton.
  • For counters use AtomicInteger/LongAdder; for compound updates use locks.

Stop Flag

Example

Without volatile, the worker could loop forever because it may never see running = false.

public class Main {
    private static volatile boolean running = true;

    public static void main(String[] args) throws InterruptedException {
        Thread worker = new Thread(() -> {
            long iterations = 0;
            while (running) {
                iterations++;
            }
            System.out.println("Worker saw running=false and stopped");
        });
        worker.start();
        Thread.sleep(200);
        running = false;
        worker.join();
        System.out.println("Main: worker finished, state = " + worker.getState());
    }
}

Output

Worker saw running=false and stopped
Main: worker finished, state = TERMINATED

volatile vs synchronized vs Atomic

VisibilityAtomic compound opsBlocks threads
volatileyesnono
synchronized / Lockyesyesyes
AtomicInteger etc.yesyes (CAS, single variable)no