Skip to main content

CAS, retry loops, and the ABA problem

advanced17 min readLesson 135 of 180

The lock-free pattern, why Aโ†’Bโ†’A fools compare-and-set, and when CAS beats locks (or loses).

CAS โ€” compare-and-set โ€” is the hardware instruction under every atomic class: "if the value is still expected, set it to next, atomically; report whether you won." Losers retry. No lock is held; the OS never schedules around you.

AtomicReference<State> ref = new AtomicReference<>(initial);
State cur, next;
do {
    cur = ref.get();
    next = derive(cur);
} while (!ref.compareAndSet(cur, next));

The ABA problem: CAS asks "is it still A?" โ€” not "did anything happen?". If the value went Aโ†’Bโ†’A between your read and your CAS, your compare passes but the world changed. Harmless for counters, fatal for stacks built on pointers: node A was freed and reallocated while you held a stale next. Java's answer: AtomicStampedReference (value + stamp, both CAS'd together) or simply avoiding shared-mutable-node designs.

CAS is optimistic (assume no interference, retry on loss); locks are pessimistic (block first). Contended CAS burns CPU retrying; contended locks park threads. High contention โ†’ locks often win. Low contention, short critical sections โ†’ CAS wins. Knowing which regime you are in is the skill.

Now practice

Lock & CAS drillsBuild deadlock-free transfers, atomic map algorithms, and a hand-rolled CAS loop that survives contention.3 challenges ยท ยท ~55 min