Why do we need 4 classes for atomic updates in Java?

April 24, 2018

Category: The package java.util.concurrent.atomic

Atomic updates are an advanced technique, typically used in high performant 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 the expected. In the example, it only updates the variable to RUNNING when the current value is NEW. If the updated succeed 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

The 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 which 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, 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, 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 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 they end up using sun.misc.Unsafe instead of AtomicReference or AtomicReferenceFieldUpdater. To see how often, 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 which should be updated atomically is declared in line 1. We create a new VarHandle with reflection by calling findVarHandle of the class MethodHandles.Lookup, line 7. We need only one VarHandle for all Instances of VarHandleExample, so we can declare the variable ATOMIC_STATE_UPDATER as static final, 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 hight 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.

testing multi-threaded applications on the JVM made easy

LEARN MORE

© 2020 vmlens Legal Notice Privacy Policy