What are the AtomicFieldUpdater classes, and why would you use one instead of wrapping every field in an AtomicInteger or AtomicReference?
answer
- One shared updater per class, not one Atomic object per instance
- Saves memory: no wrapper object/pointer per instance
- Field must be volatile + non-static + accessible
- Reflection at newUpdater() time; slower per call
- Superseded by VarHandle (Java 9)
basics
~20 sAtomicIntegerFieldUpdater, AtomicLongFieldUpdater, and AtomicReferenceFieldUpdater let you do atomic updates (like compareAndSet) on a plain volatile field of a class. You use one shared updater per class instead of giving every object its own Atomic wrapper object, which saves memory when you have huge numbers of instances.
solid answer
~50 sThe atomic field updaters (AtomicIntegerFieldUpdater, AtomicLongFieldUpdater, AtomicReferenceFieldUpdater) provide reflection-based atomic operations such as compareAndSet, getAndAdd, and getAndSet on a designated volatile field of a class, without that field being wrapped in an Atomic object. The motivation is memory: an AtomicInteger field is an extra heap object and pointer per instance, so for millions of nodes (linked-list/queue nodes, framework internals) the per-object overhead is significant. The updater is a single static final instance shared across all objects of the class, so each instance carries only a primitive/volatile field. Constraints: the field must be volatile, non-static, and accessible (typically package-private or same-class), the updater is created with reflection at class init, and it is slower per-call than a direct Atomic due to reflective access checks. Today VarHandle is the modern, faster, more general replacement, but updaters still appear in older JDK and library code.
go deeper
Knows that AtomicInteger/AtomicReference give thread-safe updates; may not have heard of field updaters. That is fine at this level.
Can explain that field updaters perform atomic CAS on a volatile field without a per-instance wrapper, and recall the volatile requirement.
Articulates the memory-vs-speed trade-off, the volatile/non-static/accessible constraints, reflective creation, and that VarHandle is the modern replacement.
Reasons about when the optimization pays off (instance counts, cache locality), the historical use in lock-free JDK/library internals, and would steer new code to VarHandle while explaining the migration cost.
## The problem being solved In Java, ordinary fields are not safe to update from multiple threads without coordination. The `java.util.concurrent.atomic` package gives you lock-free, thread-safe updates built on the hardware **compare-and-swap (CAS)** instruction. The most familiar tools are wrapper objects: `AtomicInteger`, `AtomicLong`, `AtomicReference`. You hold one of these objects and call `incrementAndGet()`, `compareAndSet(expected, new)`, etc. **CAS** means: "atomically, if this memory location currently holds value X, set it to Y and report success; otherwise do nothing and report failure." It is the primitive that lets many threads update a value without a lock. ### Why wrappers can be wasteful An `AtomicInteger` is a full Java object on the heap. If a class needs one atomically-updatable counter, giving each instance its own `AtomicInteger` means: (1) an extra object header (~12-16 bytes) per instance, (2) an extra reference field pointing to it, and (3) an extra allocation and an extra pointer-dereference on every access. For a class you instantiate millions of times — think nodes in a non-blocking queue, or framework bookkeeping objects — that overhead is real, both in heap footprint and in cache behavior (the counter lives in a separate object, hurting locality). ## What AtomicFieldUpdater is The **atomic field updater** classes invert the design. Instead of wrapping the field in an object, you keep the field as a plain `volatile int` / `volatile long` / `volatile <ReferenceType>` directly inside your class, and you create **one shared updater object per class** that knows how to perform atomic operations on that named field of any instance. The three classes are: - `AtomicIntegerFieldUpdater<T>` - `AtomicLongFieldUpdater<T>` - `AtomicReferenceFieldUpdater<T,V>` (V is the field's reference type) You obtain one with a static factory: `AtomicIntegerFieldUpdater.newUpdater(MyClass.class, "count")`. It uses **reflection** at creation time to find the field and verify constraints, then offers methods like `get(obj)`, `set(obj, val)`, `compareAndSet(obj, expect, update)`, `getAndIncrement(obj)`, `getAndAdd(obj, delta)`. Every method takes the target object as the first argument — the updater itself is stateless with respect to any particular instance. ### The constraints (and why) 1. **The field must be declared `volatile`.** The updater provides atomicity and ordering on top of the volatile field's visibility guarantees; the contract requires it. 2. **The field must be non-static** (these update instance fields). 3. **The field must be accessible from the code creating the updater** — generally it must be visible per Java access rules (commonly the field is in the same class or package). Updaters cannot reach a field they couldn't legally see; otherwise creation throws. 4. For `AtomicLongFieldUpdater`, the field is `long`; for `AtomicIntegerFieldUpdater`, `int`; for the reference one, the actual field type must match the V type argument. Violations are detected when you call `newUpdater(...)`, which throws (e.g. `IllegalArgumentException` / `RuntimeException` wrapping the reflective failure) — so you typically create the updater in a `static final` field and any mistake fails fast at class initialization. ## The memory win, concretely ``` With AtomicInteger field: [MyNode header][ref ->][AtomicInteger header][int value] With updater: [MyNode header][volatile int value] ``` The updater version removes one object and one reference per instance. The trade-off is **per-call cost**: the updater historically does an access/type check and goes through a less-direct path, so a single operation is somewhat slower than calling a method on an `AtomicInteger` directly. The design bet is that you pay slightly more per operation to save a lot of memory across many instances — worthwhile only when the instance count is large. ## Where you actually see it Updaters appear inside the JDK itself and in libraries written before VarHandle existed (Java 9). For example, non-blocking data structures and reactive-streams implementations historically used `AtomicReferenceFieldUpdater` to CAS a `next`/`state` field on huge numbers of small node/subscription objects. In application code they are relatively rare and considered a micro-optimization. ## The modern successor Since Java 9, **`VarHandle`** (from `java.lang.invoke`) is the recommended replacement. A `VarHandle` to a field offers the same field-targeted atomic operations plus a full range of memory-ordering modes, is type-checked, and the JIT optimizes it to direct machine operations — making it faster and far more general than the reflective updaters. New code should prefer `VarHandle`; updaters remain mainly for understanding and maintaining existing code. ## Summary Atomic field updaters trade a tiny per-operation cost for a large per-instance memory saving by performing CAS-style atomic ops directly on a class's `volatile` field via a single shared, reflection-built updater object — historically used in high-instance-count internals, now superseded by `VarHandle`.
- Why must the field be declared volatile when used with an atomic field updater?The updater supplies atomicity/ordering on top of the field's visibility guarantee, and its contract relies on volatile semantics for correct cross-thread visibility of the value; newUpdater rejects a non-volatile field at creation time.
- When is the per-instance memory saving actually worth the slower per-call cost?When the class is instantiated in very large numbers (millions of small objects like queue nodes), so eliminating one wrapper object + reference per instance dominates the modest extra cost paid on each atomic operation.
saying these in an interview costs you the question
- Saying the updater can target a non-volatile field — it requires volatile
- Claiming updaters are faster per-call than AtomicInteger — they trade speed for memory
- Thinking each instance needs its own updater — it is one static shared updater
- Believing updaters can update static fields — they update instance fields only
- Recommending updaters over VarHandle in new code