skip to content

Field Updaters & VarHandle

Field updaters give atomic access to volatile fields without an Atomic wrapper per instance, and VarHandle is the modern, type-safe replacement for sun.misc.Unsafe with explicit memory-ordering modes. A senior-level topic that shows you know what sits under the Atomic classes.

part ofJavaoverview, primer and where to startread it →
on this pageshow

questions

5

Given AtomicInteger, atomic field updaters, and VarHandle, how do you decide which to use for low-level atomic field access?

level: middleimportance: should knowfreq 28%

answer

  1. AtomicInteger by default — simplest, readable
  2. Field updater = shed per-instance wrapper memory (volatile field, legacy)
  3. VarHandle = new low-level: ordering modes, array CAS, Unsafe replacement
  4. Prefer highest-level tool that works; profile before dropping down
  5. Never sun.misc.Unsafe in new code

basics

~20 s

Default to AtomicInteger/AtomicReference — they are simple and clear. Drop to an atomic field updater only on legacy code or to save memory across huge numbers of instances. For new low-level code that needs custom memory ordering or array-slot CAS, use VarHandle, the modern supported replacement for both updaters and sun.misc.Unsafe.

solid answer

~50 s

Pick the highest-level tool that meets the need. For ordinary thread-safe counters or references, use the Atomic wrapper classes (AtomicInteger, AtomicLong, AtomicReference) — they are the clearest and almost always fast enough. Reach for an atomic field updater only when you must avoid the per-instance wrapper object across an enormous number of instances and you are constrained to a volatile field, or when maintaining pre-Java-9 code that already uses them. For genuinely low-level needs in new code — CAS on a field or array element, weaker memory-ordering modes (acquire/release, opaque), or replacing sun.misc.Unsafe — use VarHandle (Java 9+): it is type-safe, access-controlled via MethodHandles.Lookup, JIT-intrinsified to the same speed as Unsafe, and strictly more capable than the field updaters. In short: AtomicInteger by default, updaters for legacy/memory edge cases, VarHandle for new low-level or ordering-sensitive primitives.

go deeper

for a junior

Should default to AtomicInteger/AtomicReference for thread-safe counters and know they are the simple, safe choice.

for a middle

Can justify AtomicInteger as default and name field updaters (memory/legacy) and VarHandle (modern low-level) as the alternatives with their trade-offs.

for a senior

Articulates the constraints and costs of each and confidently steers new low-level code to VarHandle while explaining when updaters still appear.

for a principal

Sets team guidance: highest-level tool that works, profile before micro-optimizing, ban Unsafe in new code, VarHandle for ordering-sensitive primitives — and weighs the cost of migrating legacy updaters.

## Three tools, one job, different levels All three give lock-free, **compare-and-swap (CAS)**-based atomic access to a value, but at different abstraction levels and ergonomics. CAS = "atomically set the location to a new value only if it currently equals an expected value." Choosing well is mostly about **abstraction level and cost**, not capability. ### 1. Atomic wrapper classes — the default `AtomicInteger`, `AtomicLong`, `AtomicReference` (and array forms `AtomicIntegerArray`, `AtomicReferenceArray`). - **Pros:** simplest, most readable, self-documenting; the field's type makes its atomicity obvious; well-known API (`incrementAndGet`, `compareAndSet`, `updateAndGet`). - **Cons:** each wrapper is a separate heap object (header + the value) referenced by a pointer — extra memory and one more indirection per access. - **Use when:** essentially always, unless a measured constraint pushes you lower. The overhead is irrelevant for a handful of objects. ### 2. Atomic field updaters — the memory edge case `AtomicIntegerFieldUpdater`, `AtomicLongFieldUpdater`, `AtomicReferenceFieldUpdater`. - **What they buy:** atomic ops on a plain **`volatile`** field of your class via a single shared (per-class) updater, so each instance holds only the primitive/volatile field — **no wrapper object per instance**. - **Costs/constraints:** the field must be `volatile`, non-static, and accessible; the updater is built with reflection (fails fast at class init if misused); per-call cost is somewhat higher than a direct Atomic. - **Use when:** you instantiate a class in **very large numbers** and the per-instance wrapper memory matters (lock-free nodes, framework internals), **or** you are maintaining older code that uses them. For new code, VarHandle usually beats them. ### 3. VarHandle — the modern low-level primitive `java.lang.invoke.VarHandle` (Java 9, JEP 193). - **What it buys:** typed, access-checked handles to fields, **array elements**, and buffer locations, with the **full access-mode ladder** (plain/opaque/acquire-release/volatile) plus CAS family — and it is the **supported, safe, equally fast replacement for `sun.misc.Unsafe`** (intrinsified by the JIT). - **Costs:** lower-level and more verbose (static initializer + Lookup); easier to get subtly wrong with weak modes; overkill for ordinary needs. - **Use when:** writing **new** low-level concurrency primitives that need custom memory ordering (e.g. cheap acquire/release publication), per-array-element CAS, or that previously would have used `Unsafe`. ## The decision, distilled | Need | Choose | |---|---| | Ordinary thread-safe counter/reference | **AtomicInteger / AtomicReference** | | Same, but per-instance wrapper memory hurts at huge instance counts (volatile field) | **Atomic field updater** | | Maintaining pre-Java-9 code already using updaters | keep the **updater** | | New low-level primitive: custom ordering modes, array-slot CAS, or replacing Unsafe | **VarHandle** | ## Guiding principles - **Prefer the highest-level tool that works** — readability and maintainability first; drop down only for a measured reason. - **Don't micro-optimize speculatively.** Updaters and VarHandle are sharp tools; profile before reaching for them. - **For new low-level code, prefer VarHandle over updaters** — it is faster, more general, type-safe, and the platform's sanctioned path; updaters live on mainly for legacy. - **Never use `sun.misc.Unsafe` in new code** — VarHandle exists precisely so you don't have to. ## Summary Use `AtomicInteger`/`AtomicReference` by default; use an atomic **field updater** only to shed per-instance wrapper memory across huge instance counts (or in legacy code), accepting the volatile-field/reflection constraints; and use **`VarHandle`** for new low-level work needing custom memory ordering, array-element CAS, or as the safe replacement for `sun.misc.Unsafe`. The rule is to pick the highest-level option that satisfies a real, measured requirement.

  • Why might you still see atomic field updaters in modern codebases?
    Legacy: they predate VarHandle (pre-Java-9) and remain in older libraries and JDK internals; rewriting working, tested lock-free code carries risk, so they persist even though new code would use VarHandle.
  • What capability does VarHandle have that AtomicInteger and the field updaters do not?
    Explicit control over memory-ordering strength via access modes (plain/opaque/acquire-release/volatile) and uniform support for fields, array elements, and buffer locations — the Atomic classes and updaters effectively only expose volatile-strength operations.

saying these in an interview costs you the question

  • Reaching for VarHandle/updaters for an ordinary counter where AtomicInteger is fine
  • Recommending atomic field updaters over VarHandle for new code
  • Suggesting sun.misc.Unsafe at all in new code
  • Claiming field updaters are faster per-call than AtomicInteger (they save memory, not time)
  • Assuming VarHandle is slower than the alternatives because it looks low-level

context

open as a page

What are the AtomicFieldUpdater classes, and why would you use one instead of wrapping every field in an AtomicInteger or AtomicReference?

level: seniorimportance: should knowfreq 30%

basics

~20 s

AtomicIntegerFieldUpdater, 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.

open as a page

What is a VarHandle, and why was it introduced as a replacement for sun.misc.Unsafe?

level: seniorimportance: should knowfreq 38%

basics

~20 s

A VarHandle (added in Java 9) is a typed reference to a variable — a field, array element, or off-heap location — that lets you read and write it with different levels of atomicity and memory ordering, including CAS. It is the safe, supported, standard replacement for the internal, unsupported sun.misc.Unsafe.

open as a page

How do you use a VarHandle to perform atomic operations on array elements, and why is that useful?

level: seniorimportance: nice to knowfreq 18%

basics

~20 s

You create an array-element VarHandle with MethodHandles.arrayElementVarHandle(int[].class). Then operations like getVolatile or compareAndSet take the array plus an index, letting you atomically update one slot. This is useful for lock-free arrays — like a striped counter or a hash table's bucket array — without wrapping every slot in an Atomic object.

open as a page

Explain VarHandle's access modes — plain, opaque, acquire/release, and volatile — and how they differ in memory-ordering strength.

level: principalimportance: nice to knowfreq 22%

basics

~20 s

VarHandle lets you pick how strongly a read or write is ordered. Plain is a normal access with no guarantees; opaque keeps a single variable's accesses coherent and atomic; acquire/release pair up so a release write is seen by a later acquire read; volatile is the strongest, full ordering. You pick the weakest mode that is still correct, for speed.

open as a page