Atomics are the JDK's lock-free toolbox. Instead of guarding a mutable field with a lock, the java.util.concurrent.atomic classes update it with a single hardware instruction — compare-and-swap (CAS) — so threads contend on a CPU primitive rather than blocking on a monitor. The payoff is no context switches, no deadlock, and no priority inversion; the cost is a retry loop and a few sharp edges (ABA, write contention) that a senior engineer is expected to know.
The CAS primitive
CAS takes three arguments: a memory location, an expected value, and a new value. The hardware atomically checks whether the location still holds the expected value and, if so, writes the new one — all in one uninterruptible step (lock cmpxchg on x86, CASAL/LL-SC on ARM). It returns whether the swap happened. Lock-free algorithms wrap this in a read-modify-CAS-retry loop: read the current value, compute the next, and CAS; if another thread won the race, the CAS fails and you loop with the fresh value.
read current value (v)
|
compute next = f(v)
|
CAS(addr, expected=v, next)
/ \
success failure (someone else changed it)
| |
done <---------+ (loop: re-read, recompute)What the JDK gives you
AtomicInteger, AtomicLong, AtomicReference, and the array/field-updater variants expose this loop as methods: incrementAndGet, compareAndSet, getAndUpdate, accumulateAndGet. Each holds a volatile field, so reads and writes carry the same visibility and ordering guarantees as volatile — CAS is a full happens-before edge. Under heavy write contention the single hot field becomes a bottleneck (every failed CAS is wasted work and cache-line ping-pong), which is why LongAdder exists: it stripes the count across multiple cells.
ABA and the modern API
CAS only checks the value, not whether it changed and changed back. If a value goes A → B → A, a stale CAS succeeds even though the world moved underneath it — the ABA problem. The fix is to version the reference: AtomicStampedReference pairs a value with a counter so A-with-stamp-1 differs from A-with-stamp-3. Underneath all of this, Atomic* classes are built on VarHandle (since Java 9), the supported, type-safe replacement for the internal sun.misc.Unsafe that powered them historically.