Compare-and-swap (CAS) is an atomic, optimistic update: Java changes one value only if it still equals the value you read earlier. If another thread changed it first, the operation fails and a correct retry loop reads the latest value, recalculates, and tries again.
How CAS works in Java
With AtomicInteger.compareAndSet(expectedValue, newValue), Java writes newValue only when the current integer equals expectedValue. The method returns true when it performs the write and false when the observed value no longer matches. Oracle’s API describes it as: “Atomically sets the value to newValue if the current value == expectedValue.”
The canonical increment loop
AtomicInteger counter = new AtomicInteger();
for (;;) {
int oldValue = counter.get();
int newValue = oldValue + 1;
if (counter.compareAndSet(oldValue, newValue)) {
break;
}
}
The read, calculation, and conditional write form one optimistic protocol. If another thread wins between get() and compareAndSet(), the CAS fails. The loop then reads the new state and recomputes from it rather than reusing stale data.
Why the update function must tolerate retries
Contention can execute the calculation more than once. Keep calculations free of externally visible side effects such as sending a message, charging a card, incrementing a separate counter, or mutating a collection. If an update cannot safely be retried, use a design that makes the side effect idempotent or protect the whole operation with an appropriate coordination mechanism.
Free tools Windows power users keep installed
One-click scans. No signup required.
Java APIs that provide CAS
Atomic classes
AtomicInteger, AtomicLong, and AtomicReference provide ready-made atomic variables. Their array counterparts support atomic elements in an array. These classes are usually the clearest choice when the state is one integer, long, or reference.
VarHandle
VarHandle exposes lower-level access modes, including compare-and-set and compare-and-exchange operations. It also lets an algorithm choose volatile, acquire, release, plain, or weak variants. The ordering mode is part of the algorithm’s correctness contract, not merely a speed setting.
Rank #2
Choosing among CAS methods
| Operation | Use it when | Result |
|---|---|---|
compareAndSet |
You need to know only whether the update succeeded. | Boolean success or failure. |
compareAndExchange |
You need the value that was actually observed. | The witness value; on success it equals the expected value. |
| Weak compare-and-set forms | You already have a retry loop and can handle occasional spurious failure. | May fail even when the expected value matches; use the ordering variant required by the algorithm. |
Use the strongest ordering that your publication and visibility requirements need, but do not infer the Java Memory Model from a particular processor’s behavior.
CAS and memory visibility
Atomicity answers one question—whether a conditional update is indivisible. It does not by itself explain how unrelated reads and writes become visible between threads. The Java Memory Model, specified through JSR-133, defines the happens-before relationships involving threads, locks, volatile variables, and data races.
VarHandle modes make those relationships explicit:
- Volatile: volatile-style visibility and ordering.
- Acquire: orders subsequent operations after a successful read-like access.
- Release: orders prior operations before a write-like access.
- Plain: deliberately provides no synchronization ordering beyond the mode’s basic access rules.
Document which read, write, or successful CAS establishes the happens-before edge your algorithm relies on. A CAS loop that updates a counter may be correct with one ordering, while a publication protocol for an object graph may require another.
What CAS cannot make atomic
A CAS operation covers one atomic location. It does not transactionally update several independent fields. For example, changing a balance and a transaction status in separate locations can expose an intermediate state even if each location is individually atomic.
Rank #4
When an invariant spans multiple values, use one of these designs:
- A lock: guard all related fields while the invariant is changed.
- Immutable combined state: place all fields in one immutable object and atomically publish a new reference.
- A descriptor or versioned protocol: coordinate multi-step changes with a carefully designed algorithm that readers understand.
The ABA problem
ABA occurs when a thread reads value A, another thread changes A to B and then back to A, and the first thread’s CAS sees A again. The comparison succeeds even though the location changed during the interval. For a reference algorithm, that can make a removed-and-reinserted node appear untouched.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Fix the driver behind crashes, sound loss and screen glitches3Repair Windows errors before they cause bigger problemsBest Value
AtomicStampedReference pairs the reference with a version stamp. Each logical change can advance the stamp, allowing a CAS to detect that the reference passed through another state even when the reference value returned to A. Versioning addresses the comparison ambiguity; it does not automatically solve every lifetime, reclamation, or multi-object invariant problem in a lock-free data structure.
Is CAS lock-free?
CAS is a primitive used to build nonblocking algorithms, but the presence of a CAS instruction does not prove that an entire algorithm is lock-free.
- Obstruction-free: a thread can finish when it runs alone for long enough.
- Lock-free: the system as a whole keeps making progress; some thread completes even if individual threads can repeatedly lose races.
- Blocking: progress may depend on a thread releasing a lock or another parked thread waking.
A retry loop can be lock-free yet still starve one unlucky thread. Under heavy contention, repeated failed attempts also consume CPU. A design may need bounded retries, backoff, batching, or a lock-based fallback. Whether CAS outperforms locking depends on contention, the JVM, the processor, and the amount of work in each attempt; there is no universal performance winner.
Quick Recap
CAS versus synchronized
| Decision factor | CAS-based update | synchronized or a lock |
|---|---|---|
| Invariant scope | Best suited to one atomic value or one atomically published reference. | Can protect several fields and operations as one critical section. |
| Contention behavior | Threads retry or spin; wasted CPU and starvation are possible. | Losers wait for ownership; blocking avoids an unbounded retry loop. |
| Memory ordering | Must be selected and documented through the atomic or VarHandle access mode. | Lock entry and exit provide the lock’s defined visibility and ordering. |
| Progress guarantee | May be obstruction-free or lock-free, depending on the complete algorithm. | Blocking; progress depends on lock availability and the holder’s behavior. |
| ABA and reclamation risk | Reference algorithms may require stamps, versions, or other protection. | Critical-section ownership can simplify reasoning about shared state. |
How to choose an implementation
- Identify the invariant. If one integer, long, or reference is the entire state, an atomic class is a natural starting point. If several fields must change together, begin with a lock or a single immutable state object.
- Specify visibility. Decide which operations publish data and which operations consume it. Select volatile, acquire, release, plain, or the corresponding atomic-class semantics accordingly.
- Design the retry path. Re-read after failure, recompute from the fresh value, and ensure every attempted calculation is safe to repeat.
- Bound pathological contention. Consider a retry limit, backoff, queueing, or a lock fallback when endless spinning would harm latency or CPU consumption.
- Check for ABA. If a reference can leave and later return to the same value, add a stamp or version, or choose a design whose ownership rules eliminate that ambiguity.
- Validate progress claims. Call an algorithm lock-free only after analyzing all loops, helping steps, fallback paths, and possible starvation—not merely because it contains CAS.
Practical checklist
- Use
AtomicInteger,AtomicLong,AtomicReference, or their array forms for standard atomic variables. - Use
VarHandlewhen you need explicit access modes or lower-level layouts. - Prefer
compareAndSetwhen a boolean is sufficient; usecompareAndExchangewhen the observed value matters. - Use weak CAS only inside a retry strategy that tolerates spurious failure.
- Do not treat CAS as a transaction over multiple locations.
- Do not put non-idempotent side effects inside a retryable update function.
- Use versioning such as
AtomicStampedReferencewhen ABA can invalidate a reference comparison. - Keep the required happens-before relationship explicit in code comments and design documentation.
- Do not use
Unsafeas the teaching-level interface when supported atomic classes orVarHandleprovide the needed operation.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

