"What is CAS, and what is the ABA problem?"
CAS is the foundation of lock-free programming in Java. The ABA problem tests whether you understand the fundamental weakness of simple CAS and know the ecosystem of tools — AtomicStampedReference — designed to address it.
CAS (Compare-And-Swap) is an atomic CPU instruction: "if memory at address X still equals expected value E, write new value N; else do nothing". Returns whether the swap succeeded.
Java exposes CAS via sun.misc.Unsafe (and VarHandle in Java 9+). AtomicInteger, AtomicLong, ConcurrentHashMap are built on it. The typical pattern is a while loop: read current, compute new, CAS; if CAS fails someone else beat us to it, retry.
ABA problem: thread T1 reads value A. Before T1's CAS, thread T2 changes A → B → A. T1's CAS sees A and succeeds, but the underlying state has actually moved and T1's view is stale.
Concrete scenario: lock-free stack. T1 wants to CAS head from node A to A.next. Between T1's read and CAS, T2 pops A, pops B, pushes A back — head equals A again but the linked list is completely different. T1's CAS succeeds but sets head to a stale next pointer, corrupting the stack.
Fix: AtomicStampedReference pairs the value with a monotonically increasing stamp. CAS now checks value AND stamp; any intermediate change bumps the stamp, so ABA is detectable.
CAS is a hardware atomic instruction — compare-and-swap — with the semantic "if memory at address X currently equals expected value E, atomically replace it with new value N and return success; otherwise leave it alone and return failure." It's the building block of non-blocking concurrency. In Java you touch it through Unsafe or VarHandle, and AtomicInteger, AtomicLong, and even ConcurrentHashMap's bucket CAS are all built on it. The typical usage pattern is a retry loop: read current, compute new value, CAS; if someone else modified the field between the read and the CAS, CAS fails and you retry. The ABA problem is CAS's fundamental weakness. Thread T1 reads value A intending to CAS. Before T1 gets to execute the CAS, thread T2 changes A to B and then back to A. When T1 finally executes its CAS, it sees A and succeeds — but the underlying state has moved through an intermediate value and may be semantically different than it was when T1 first observed A. For primitive counters this rarely matters. For reference-based lock-free structures it's disastrous. Classic example: a lock-free stack where head is an AtomicReference. T1 reads head=A, plans to CAS head from A to A.next. Meanwhile T2 pops A (head becomes B), pops B (head becomes null), allocates a new node that happens to reuse A's memory, and pushes it (head becomes A again). T1's CAS sees A and succeeds, setting head to A.next — but A.next from the original view is pointing at B, which has since been freed/popped. Now the stack's head points into invalid memory. The fix is AtomicStampedReference: it wraps value + int stamp. Every set bumps the stamp, and compareAndSet checks both value and stamp match. Any intermediate write, even if the value returns to A, changes the stamp so the CAS fails and retry kicks in. AtomicMarkableReference is similar with a boolean mark, useful for "deleted" flags. In practice, primitive atomic counters don't need this; it's reference-based lock-free data structures where ABA bites.
Give a concrete ABA example with a stack or queue — saying "it's a problem" without a scenario sounds textbook.
Mentioning AtomicStampedReference by name is the right level of specificity.
Distinguish where ABA matters (references/memory) vs. where it rarely does (primitive counters).
If you blank on AtomicStampedReference during the interview, HireMe AI can surface its name.
CAS is usually much faster under low contention (no system call, no thread park). Under heavy contention retries pile up and locks can win — LongAdder avoids this with striping.
Yes — CAS acquires the cache line exclusively, so heavy contention on one variable causes cache-line ping-pong between CPUs and degrades badly.
On some architectures (ARM LL/SC), CAS can fail spuriously due to context switches or cache events — you must retry in a loop, which the standard while(!CAS) pattern already does.
HireMe AI listens to your interview in real-time, detects questions, and generates instant answer suggestions — so you never freeze up again.
Try HireMe AI Free