Medium java java-21

What is the difference between volatile and AtomicInteger?

The 30 second answer

Volatile only guarantees visibility and ordering: every thread sees the latest write to that variable. But count plus plus is a read, an add and a write, so two threads can still lose updates with volatile. AtomicInteger makes the whole increment atomic using compare-and-set, without a lock. So I use volatile for a simple stop flag and atomics for counters; under heavy contention, LongAdder.

volatile boolean running = true;     // fine: one writer, others only read
volatile int count;  count++;        // broken: lost updates under contention

AtomicInteger hits = new AtomicInteger();
hits.incrementAndGet();
hits.updateAndGet(x -> Math.min(x + 1, 100));
hits.compareAndSet(expected, newValue);

A write to a volatile field happens-before every later read of that field, so it also safely publishes the writes made before it. It does not make compound operations atomic.

Atomic classes are built on compare-and-set (CAS): read the value, compute the new one, and swap only if nobody changed it meanwhile; otherwise retry.

Under heavy contention many threads keep retrying the same CAS. LongAdder spreads updates across cells and sums them on read; its Javadoc says it has higher throughput under high contention at the cost of more space. Its sum() is not an atomic snapshot, so use it for statistics, not IDs or sequence numbers.

Sources: JLS 8.3.1.4 volatile Fields, JLS 17.4.5 Happens-before Order, AtomicInteger Javadoc, LongAdder Javadoc

Sources (0)
See inline citations in the answer above.