How do you use a VarHandle to perform atomic operations on array elements, and why is that useful?
answer
- MethodHandles.arrayElementVarHandle(T[].class)
- Coordinates are (array, index) at every call
- Per-element CAS/volatile without an Atomic wrapper per slot
- Underlies AtomicIntegerArray / AtomicReferenceArray
- Use for striped counters, concurrent-map buckets, ring buffers
basics
~20 sYou 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.
solid answer
~40 sMethodHandles.arrayElementVarHandle(SomeType[].class) returns a VarHandle whose coordinates are (the array, the index). You then call get/set/getVolatile/setRelease/compareAndSet/getAndAdd passing the array and the element index, giving you per-element atomic and ordered access without an AtomicReferenceArray/AtomicIntegerArray wrapper or a separate Atomic object per slot. It is useful for building lock-free structures over a backing array — striped counters, bucket arrays in concurrent maps, ring buffers — where you want CAS on individual slots cheaply and with a chosen memory-ordering mode. The handle also enforces the array's component type at access time. Compared with AtomicIntegerArray (which is itself built on this mechanism), a raw VarHandle gives you the full ladder of access modes rather than just volatile-strength operations, which matters for tuning hot data structures.
code
java · 27 linesimport java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
class StripedCounter {
private final long[] cells;
private static final VarHandle CELLS =
MethodHandles.arrayElementVarHandle(long[].class);
StripedCounter(int stripes) { this.cells = new long[stripes]; }
// Each caller hits a cell (e.g. by thread hash) to cut CAS contention.
void add(int cell, long delta) {
long prev, next;
do {
prev = (long) CELLS.getVolatile(cells, cell);
next = prev + delta;
} while (!CELLS.compareAndSet(cells, cell, prev, next));
}
long sum() {
long total = 0;
for (int i = 0; i < cells.length; i++) {
total += (long) CELLS.getVolatile(cells, i);
}
return total;
}
}go deeper
Not expected; knowing arrays aren't thread-safe by default is sufficient at this level.
Can recall that AtomicIntegerArray/AtomicReferenceArray exist for atomic per-element updates; VarHandle array access is advanced.
Can create an array-element VarHandle, call CAS/volatile with the (array,index) coordinates, and explain its use in lock-free arrays.
Designs striped/lock-free array structures choosing per-operation access modes, understands the relation to AtomicIntegerArray and alignment constraints on view handles.
## The need Sometimes the thing you want to update atomically is **one element of an array**, not a standalone field. Classic cases: a **striped counter** (an array of cells updated by different threads to reduce contention — the idea behind `LongAdder`), the **bucket array** of a concurrent hash table, or slots of a **ring buffer** in a lock-free queue. You want to CAS or volatile-read a single slot, with as little overhead as possible, and ideally with control over memory ordering. Java's older answer was wrapper classes like `AtomicIntegerArray` and `AtomicReferenceArray` — objects that wrap an array and expose `get(i)`, `set(i, v)`, `compareAndSet(i, exp, new)`. They work but lock you into volatile-strength operations and add a wrapper object. ## The VarHandle way `java.lang.invoke.MethodHandles` provides a factory specifically for array elements: ```java VarHandle AH = MethodHandles.arrayElementVarHandle(int[].class); ``` The returned VarHandle has **two coordinate types**: the array itself and an `int` index. So every access takes those plus any operands: ```java int[] arr = new int[16]; int old = (int) AH.getVolatile(arr, 3); // volatile read of arr[3] AH.setRelease(arr, 3, 42); // release write of arr[3] boolean ok = AH.compareAndSet(arr, 3, 42, 43); // CAS on arr[3] int prev = (int) AH.getAndAdd(arr, 3, 5); // atomic add to arr[3] ``` Key points: - **No per-slot wrapper.** You operate directly on the primitive (or reference) elements of an ordinary array — no `Atomic*` object per slot and no `AtomicIntegerArray` wrapper. - **Full access-mode ladder.** Just like field VarHandles, array-element handles support plain/opaque/acquire-release/volatile reads and writes, plus `compareAndSet`, `weakCompareAndSet`, `getAndAdd`, etc. You pick the ordering strength per operation. - **Type and bounds safety.** The component type is fixed when you create the handle (`int[].class` here), and element access is bounds-checked like normal array access, so you keep Java's safety — unlike raw offset arithmetic in `sun.misc.Unsafe`. - **One handle for the whole array type.** A single `static final` VarHandle works for any array of that component type; you pass the specific array and index at call time. ## Reference arrays and the contended case For object arrays you create the handle over the reference array type, e.g. `MethodHandles.arrayElementVarHandle(Node[].class)`, and CAS references into slots — exactly what a concurrent hash map does when installing a node into a bucket. For **highly contended counters**, striping updates across many array cells (each thread mostly hits its own cell) reduces CAS contention; `LongAdder` embodies this strategy, and a hand-rolled version would use an array-element VarHandle. ## Why prefer it over AtomicIntegerArray `AtomicIntegerArray` is actually implemented on top of this same machinery. Using the VarHandle directly buys you: (1) the **weaker/cheaper access modes** (e.g. acquire/release publication) that the wrapper doesn't expose, (2) no wrapper allocation if you already have the array, and (3) uniform code with your field VarHandles. The cost is that it is lower-level and easier to misuse, so it belongs in carefully written data-structure code rather than everyday logic. ## A subtlety: alignment and byte-buffer views Beyond plain element arrays, related factories (`byteArrayViewVarHandle`, `byteBufferViewVarHandle`) let you read/write multi-byte values out of a `byte[]`/`ByteBuffer` with a chosen endianness and access mode — but atomic modes there require proper **alignment**, or they throw. That's an advanced corner; the core array-element handle is the common tool. ## Summary An array-element VarHandle (from `MethodHandles.arrayElementVarHandle`) has coordinates (array, index) and lets you perform the full ladder of atomic/ordered operations on individual array slots — no per-slot Atomic wrapper, with type and bounds safety. It underlies `AtomicIntegerArray`/`AtomicReferenceArray` and is the tool for lock-free arrays like striped counters, concurrent-map bucket arrays, and ring buffers, giving finer ordering control than the wrapper classes.
- What advantage does a raw array-element VarHandle have over AtomicIntegerArray?It exposes the full access-mode ladder (plain/opaque/acquire-release/volatile) instead of only volatile-strength operations, avoids a wrapper allocation when you already hold the array, and keeps your concurrency code uniform with field VarHandles — at the cost of being lower-level.
- How does an array-element VarHandle relate to building a LongAdder-style striped counter?You back the counter with a long[] and CAS individual cells via the array-element handle, so different threads update different cells and contention on any one CAS drops — exactly the striping LongAdder uses to scale write throughput.
saying these in an interview costs you the question
- Thinking you need an Atomic object per array slot — the handle works on raw elements
- Forgetting to pass the index coordinate to each access
- Assuming array VarHandles skip bounds checks — element access is still bounds-checked
- Believing byte-buffer-view atomic access works at any offset — it requires alignment
- Claiming AtomicIntegerArray is unrelated — it is built on the same mechanism