A VarHandle provides typed access to a variable with selected memory-order and atomic-update operations; its access mode is part of the operation contract.
Java VarHandle: atomic transitions and explicit access modes
This program targets Java 11 without preview flags. Use a full JDK for compiler-based examples.
A transition is narrower than a workflow
A receipt begins unclaimed. One worker attempts to change its state from zero to one. compareAndSet makes that conditional transition indivisible for the selected field. A second claim against zero fails after the first succeeds, so the caller can reject duplicate work without a separate read-then-write race.
This is not an entire processing transaction. After the claim, a network operation can fail or the process can stop. The application still needs a recovery state and an idempotent external operation. Atomic ownership of one field does not supply either of those.
Choose the access mode deliberately
Plain, opaque, acquire/release and volatile modes offer different ordering rules. Reading a state with acquire requires an appropriate publication protocol; it does not turn unrelated unsynchronized writes into a valid design by naming the mode. The program uses compareAndSet and getVolatile to show a simple atomic state change without claiming to prove every weaker-mode protocol.
A handle includes receiver and value types. For an instance integer field, passing a different receiver or a long value can produce a type error at invocation. The lookup also follows access-control rules. Resolve the handle once and keep the field contract visible near the state definition.
Working program
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
public class ClaimedReceiptState {
private volatile int state;
private static final VarHandle STATE;
static {
try { STATE = MethodHandles.lookup().findVarHandle(ClaimedReceiptState.class, "state", int.class); }
catch (ReflectiveOperationException failure) { throw new ExceptionInInitializerError(failure); }
}
public static void main(String[] args) {
ClaimedReceiptState receipt = new ClaimedReceiptState();
System.out.println(STATE.compareAndSet(receipt, 0, 1));
System.out.println(STATE.compareAndSet(receipt, 0, 1));
System.out.println((int) STATE.getVolatile(receipt));
}
}Output
true
false
1Costs and boundaries
The example performs three bounded field operations. Under contention, the hardware and runtime determine retry and ordering costs; a CAS-based retry loop can consume work without making a system-wide latency guarantee. Use this primitive when its ownership protocol is simpler to explain than an ordinary lock, not merely because it avoids the word synchronized.
Common Mistakes
- Do not use plain access when the publication rule requires ordered access.
- Weak CAS variants can fail without an observed value change.
- One CAS does not commit several unrelated structures.
