Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Why Do We Need 4 Classes for Atomic Updates in Java?

DZone's Guide to

Why Do We Need 4 Classes for Atomic Updates in Java?

Java has made atomic updates a bit confusing. Let's run through the four classes up for consideration and cover their ideal use cases for clarity.

· Java Zone ·
Free Resource

Verify, standardize, and correct the Big 4 + more– name, email, phone and global addresses – try our Data Quality APIs now at Melissa Developer Portal!

Atomic updates are an advanced technique, typically used in high-performance concurrent data structures. Atomic updates are, for example, heavily used in the package java.util.concurrent. So why do we need 4 classes for atomic updates in Java?

By looking at each class, we will see which class should be used for what. And by looking at the reason for those 4 classes, we see what to look for when implementing a high and low-level API. But let us start with the easiest of the four classes: AtomicReference

First Class: AtomicReference

The easiest way to call compare and set is to use the method compareAndSet from the class AtomicReference. The class CommandReader from the maven surefire plugin uses the compareAndSet method of AtomicReference to implement a concurrent state machine:

public final class CommandReader {
    private static final CommandReader READER = new CommandReader();
    private final Thread commandThread = 
        newDaemonThread( new CommandRunnable(), "surefire-forkedjvm-command-thread" );
    private final AtomicReference<Thread.State> state =
       new AtomicReference<Thread.State>( NEW );
    public static CommandReader getReader() {
        final CommandReader reader = READER;
        if ( reader.state.compareAndSet( NEW, RUNNABLE ) ) {
            reader.commandThread.start();
        }
        return reader;
    }
}


The class AtomicReference wraps another class to enrich a variable with atomic update functionality. In line 5, the AtomicReference represents an atomic variable of the Enum type Thread.State. The AtomicReference gets initialized in line 6 to the value NEW. The compareAndSet method only updates its value to the new value when the current value is the same as expected. In the example, it only updates the variable to RUNNING when the current value is NEW. If the update succeeds, the method returns true and the thread gets started. Otherwise, it returns false and nothing happens.

The disadvantage of AtomicReference is that for each Object we want to update atomically, we need a separate AtomicReference instance. With the OpenJDK tool jol, we see that, for our example, the AtomicReference costs two-thirds of the object Thread.State:

public static void main(String[] args) {
    out.println(VM.current().details());
    out.println(ClassLayout.parseClass(AtomicReference.class).toPrintable());
    out.println(ClassLayout.parseClass(Thread.State.class).toPrintable());
}


And here the output:

# Running 64-bit HotSpot VM.
java.util.concurrent.atomic.AtomicReference object internals:
Instance size: 16 bytes
java.lang.Thread$State object internals:
Instance size: 24 bytes


Therefore, Java provides a second class, AtomicReferenceFieldUpdater, to call compareAndSet using reflection.

Second Class: AtomicReferenceFieldUpdater

AtomicReferenceFieldUpdater uses reflection to access the field to update atomically:

private volatile Thread.State state = NEW;
private static final AtomicReferenceFieldUpdater<AtomicReferenceExample, Thread.State> 
    ATOMIC_STATE_UPDATER =  AtomicReferenceFieldUpdater.
        newUpdater(AtomicReferenceExample.class, Thread.State.class, "state");
public void update() {
    ATOMIC_STATE_UPDATER.compareAndSet(this, NEW, RUNNABLE);
}


The volatile field that should be updated atomically is declared in line 1. A new AtomicReferenceFieldUpdater is created with the name of the field, the class of the field, and the class containing the field on line 3. The field holding the AtomicReferenceFieldUpdater is static final since we need only one AtomicReferenceFieldUpdater for all objects. To update a field, we call compareAndSet with the object we want to update, the expected and the new value, as seen on line 5.

Third Class: sun.misc.Unsafe

To see the third way, let us look at the implementation of AtomicReferenceFieldUpdater.

private static final class AtomicReferenceFieldUpdaterImpl<T,V>
    extends AtomicReferenceFieldUpdater<T,V> {
        private static final Unsafe unsafe = Unsafe.getUnsafe();
        private final long offset;
        AtomicReferenceFieldUpdaterImpl(final Class<T> tclass,
                                            final Class<V> vclass,
                                            final String fieldName,
                                            final Class<?> caller) {
             final Field field;
             field = AccessController.doPrivileged(
             new PrivilegedExceptionAction<Field>() {
                 public Field run() throws NoSuchFieldException {
                     return tclass.getDeclaredField(fieldName);
                 }
             });
             // parameter checks and exception handling omitted 
             offset = unsafe.objectFieldOffset(field);
        }
        public boolean compareAndSet(T obj, V expect, V update) {
            if (obj == null || obj.getClass() != tclass || cclass != null ||
                (update != null && vclass != null &&
                vclass != update.getClass()))
                updateCheck(obj, update);
        return unsafe.compareAndSwapObject(obj, offset, expect, update);
    }
}


AtomicReferenceFieldUpdater is a wrapper around the class sun.misc.Unsafe, adding security checks and making the API easier. To use the method compareAndSwapObject from sun.misc.Unsafe, we need the offset of the field we want to update. The offset is calculated in the constructor on line 17. To update an object, we call compareAndSwapObject with the object we want to update, the offset, the expected state, and the new state, line 24.

Usage Count

Many people do what we did. They look at the implementation of AtomicReference and AtomicReferenceFieldUpdater and sometimes end up using sun.misc.Unsafe instead of AtomicReference or AtomicReferenceFieldUpdater. To see how often that happens, let us look at the GitHub open source projects using Google BigQuery. Google BigQuery allows you to query GitHub projects using SQL. We use the following query to get the usage count:

SELECT count(*) FROM (
      SELECT SPLIT(repo.content, '\n') line
      FROM [fh-bigquery:github_extracts.contents_java] as repo
      HAVING REGEXP_MATCH(line, [Search Key]) 
)


The used table fh-bigquery:github_extracts.contents_java was last updated Jan 19, 2017. Here are the results for the three search keys:

Search Key Count
java.util.concurrent.atomic.AtomicReference; 20746
compareAndSwapObject 3454
java.util.concurrent.atomic.AtomicReferenceFieldUpdater; 896


AtomicReference is most often used, followed by the usage of Unsafe.

AtomicReferenceFieldUpdater, on the other hand, is only seldom used.

I use compareAndSwapObject as the search key for sun.misc.Unsafe since the sun.misc.Unsafe provides methods for multiple use cases. And compareAndSwapObject uniquely identifies the usage sun.misc.Unsafe for an atomic update of a reference variable.

Fourth Class: VarHandle

But with the release of JDK 9, Oracle wanted to clean up. The first idea, to simply forbid the usage of sun.misc.Unsafe using the new module system, led to a public outcry in the community. This outcry led to an update to the JDK Enhancement Proposal 260: Encapsulate Most Internal APIs. It now states that all methods which have a replacement in JDK 9 will be deprecated and removed in a later release. The replacement in JDK 9 for objectFieldOffset of sun.misc.Unsafe is the class VarHandle.

The JDK Enhancement Proposal for the class VarHandle is JEP 193: Variable Handles. I think the most important sentence for a higher usage of the class VarHandle instead of sun.misc.Unsafe from the community is the penultimate sentence of this JEP:

The classes in java.util.concurrent (and other areas identified in the JDK) will be migrated from sun.misc.Unsafe to VarHandle.

The following shows the usage of a VarHandle to update our state variable:

private volatile Thread.State state = NEW;
private static final VarHandle ATOMIC_STATE_UPDATER;
static {
    try {
    MethodHandles.Lookup l = MethodHandles.lookup();
    ATOMIC_STATE_UPDATER = 
        l.findVarHandle(VarHandleExample.class, "state", Thread.State.class);
    } 
    catch (ReflectiveOperationException e) {
         throw new Error(e);
    }
}
public void update() {
    ATOMIC_STATE_UPDATER.compareAndSet(this, NEW, RUNNABLE);
}


A VarHandle works almost the same as AtomicReferenceFieldUpdater. The volatile field that should be updated atomically is declared in line 1. We create a new VarHandle with reflection by calling findVarHandle of the class MethodHandles.Lookup in line 7. We need only one VarHandle for all Instances of VarHandleExample, so we can declare the variable ATOMIC_STATE_UPDATER as static final in line 2. To update a field, we call compareAndSet with the object we want to update, the expected and the new value, line 14.

Summary and Next Steps

If you want to use compare and set in your application, use AtomicReference. It is the easiest class of the four. This post shows that AtomicReference is sometimes even easier to use than a synchronized block. And if you want to learn how to implement high performant concurrent data structures using AtomicReference, read the book The Art of Multiprocessor Programming.

Our 4 classes show that if you want to provide low and high-level API, do not offer an API with medium complexity like AtomicReferenceFieldUpdater. And the low-level API should be so useful that it is used in your own classes, like VarHandle in the package java.util.concurrent. But I think the main lesson is nobody gets all classes right all the time.

Developers! Quickly and easily gain access to the tools and information you need! Explore, test and combine our data quality APIs at Melissa Developer Portal – home to tools that save time and boost revenue. Our APIs verify, standardize, and correct the Big 4 + more – name, email, phone and global addresses – to ensure accurate delivery, prevent blacklisting and identify risks in real-time.

Topics:
java ,concurrent programming ,atomic updates ,best practices ,atomicreference ,atomicreferencefieldupdater ,sun.misc.unsafe ,varhandle ,tutorial

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}