Skip to main content
  1. Java Concurrency (java.util.concurrent)/

Advanced Atomics

4 mins

Beyond AtomicInteger and AtomicLong, java.util.concurrent.atomic provides tools for complex state management in a lock-free way.

AtomicReference #

View Source on GitHub

AtomicReference provides atomic updates for object references. It is the core of most lock-free data structures that need to link or unlink nodes.

Canonical Usage: Use AtomicReference when you have a complex state object that must be updated as a single unit or when you need to perform an atomic “swap” of an entire configuration object.

AtomicReference<Config> config = new AtomicReference<>(new Config());

// Atomic swap
Config oldConfig = config.getAndSet(newConfig);

// Complex CAS update
config.updateAndGet(c -> c.withNewProperty("new-value"));

Implementation Details #

AtomicReference Structure #

public class AtomicReference<V> implements java.io.Serializable {
    private static final VarHandle VALUE = MhUtil.findVarHandle(
        MethodHandles.lookup(), "value", Object.class);
    
    @SuppressWarnings("serial") // Conditionally serializable
    private volatile V value;
}

Core Operations #

compareAndSet:

public final boolean compareAndSet(V expectedValue, V newValue) {
    return VALUE.compareAndSet(this, expectedValue, newValue);
}

getAndSet:

public final V getAndSet(V newValue) {
    return (V)VALUE.getAndSet(this, newValue);
}

Functional Updates (Java 8+) #

public final V getAndUpdate(UnaryOperator<V> updateFunction) {
    V prev = get(), next = 0;
    for (boolean haveNext = false;;) {
        if (!haveNext)
            next = updateFunction.apply(prev);
        if (weakCompareAndSetVolatile(prev, next))
            return prev;
        haveNext = (prev == (prev = get()));
    }
}

public final V updateAndGet(UnaryOperator<V> updateFunction) {
    V prev = get(), next = 0;
    for (boolean haveNext = false;;) {
        if (!haveNext)
            next = updateFunction.apply(prev);
        if (weakCompareAndSetVolatile(prev, next))
            return next;
        haveNext = (prev == (prev = get()));
    }
}

Accumulate Operations #

public final V getAndAccumulate(V x,
                               BinaryOperator<V> accumulatorFunction) {
    V prev = get(), next = 0;
    for (boolean haveNext = false;;) {
        if (!haveNext)
            next = accumulatorFunction.apply(prev, x);
        if (weakCompareAndSetVolatile(prev, next))
            return prev;
        haveNext = (prev == (prev = get()));
    }
}

Memory Ordering Variants #

Volatile (default):

public final boolean compareAndSet(V expect, V update) {
    return VALUE.compareAndSet(this, expect, update);
}

Plain (weaker semantics):

public final boolean weakCompareAndSetPlain(V expect, V update) {
    return VALUE.weakCompareAndSetPlain(this, expect, update);
}

Lazy Set:

public final void lazySet(V newValue) {
    VALUE.setRelease(this, newValue);
}

FieldUpdaters #

View Source on GitHub

AtomicIntegerFieldUpdater, AtomicLongFieldUpdater, and AtomicReferenceFieldUpdater allow you to perform atomic updates on volatile fields of other classes using reflection.

Canonical Usage: Use field updaters instead of wrapping a field in an AtomicInteger when you have thousands or millions of small objects (e.g., millions of nodes in a massive graph). An AtomicInteger is a separate object with its own header (12-16 bytes). A field updater is a single static instance that can update fields in any number of target objects without extra object overhead.

public class Node {
    private volatile int state;
    
    private static final AtomicIntegerFieldUpdater<Node> stateUpdater =
        AtomicIntegerFieldUpdater.newUpdater(Node.class, "state");

    public void lock() {
        stateUpdater.compareAndSet(this, 0, 1);
    }
}

Implementation Details #

FieldUpdater Creation #

@CallerSensitive
public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass,
                                                          String fieldName) {
    return new AtomicIntegerFieldUpdaterImpl<U>
        (tclass, fieldName, Reflection.getCallerClass());
}

The factory method:

  1. Validates the field exists and is volatile int
  2. Checks accessibility using reflection
  3. Returns a concrete AtomicIntegerFieldUpdaterImpl instance

Core Operations #

compareAndSet:

public abstract boolean compareAndSet(T obj, int expect, int update);

getAndSet:

public abstract int getAndSet(T obj, int newValue);

getAndIncrement:

public int getAndIncrement(T obj) {
    return getAndAdd(obj, 1);
}

Implementation Class #

The concrete implementation uses Unsafe:

private static final class AtomicIntegerFieldUpdaterImpl<T>
    extends AtomicIntegerFieldUpdater<T> {
    
    private final long offset;
    private final Unsafe unsafe;
    
    AtomicIntegerFieldUpdaterImpl(Class<T> tclass, String fieldName, Class<?> caller) {
        // Reflection validation and offset calculation
        this.offset = U.objectFieldOffset(field);
        this.unsafe = U;
    }
    
    public boolean compareAndSet(T obj, int expect, int update) {
        return unsafe.compareAndSetInt(obj, offset, expect, update);
    }
    
    public int getAndSet(T obj, int newValue) {
        return unsafe.getAndSetInt(obj, offset, newValue);
    }
}

Memory Layout Efficiency #

Without FieldUpdater (AtomicInteger wrapper):

class Node {
    AtomicInteger state = new AtomicInteger(); // 12-16 byte header + 4 byte int
    // Total: ~16-20 bytes per Node
}

With FieldUpdater:

class Node {
    volatile int state; // 4 bytes
    // Total: 4 bytes per Node
    // Shared updater instance: one per class
}

For 1M nodes: 12-16MB savings

Limitations #

  1. Field must be volatile: Non-volatile fields cause IllegalArgumentException
  2. No final fields: Final fields cannot be updated atomically
  3. Access control: Field must be accessible to the caller
  4. Weaker guarantees: Only guarantees atomicity with respect to other invocations on the same updater
  5. Performance overhead: Reflection-based validation on creation

Best Practices #

// Correct: static final field updater
private static final AtomicIntegerFieldUpdater<Node> stateUpdater =
    AtomicIntegerFieldUpdater.newUpdater(Node.class, "state");

// Anti-pattern: creating updaters repeatedly
public void update() {
    // DON'T DO THIS - creates new updater on every call
    AtomicIntegerFieldUpdater<Node> updater =
        AtomicIntegerFieldUpdater.newUpdater(Node.class, "state");
    updater.incrementAndGet(this);
}

AtomicStampedReference #

AtomicStampedReference maintains an object reference along with an integer “stamp” that can be updated atomically. It is designed to solve the ABA problem in lock-free programming, where a value is changed from A to B and then back to A, causing a simple CAS to succeed incorrectly.