I've used atomic references a lot in writing NiFi processors, but there's a lot I don't know about the topic—just the stuff I've used. Here's an excerpt from something I stumbled upon once that makes for good notes useful in the future. This isn't well enough written to be one of my topics, but it serves the purpose of a good note.
In essence, AtomicReference wraps another class, here Thread.State, to add atomic update functionality to that class. The compareAndSet() method only updates the atomic variable to RUNNING when the current value is (still) NEW.
public final class CommandReader { private static final String THREAD_NAME = "surefire-forkedjvm-command-thread"; private static final CommandReader READER = new CommandReader(); private final Thread commandThread = newDaemonThread( new CommandRunnable(), THREAD_NAME ); private final AtomicReference< Thread.State > state = new AtomicReference<>( NEW ); public static CommandReader getReader() { final CommandReader reader = READER; if ( reader.state.compareAndSet( NEW, RUNNABLE ) ) reader.commandThread.start(); return reader; } }
If we test this code thus:
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() ); }
...we see:
# 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
...uses reflection to access the field to be updated atomically:
// (compare this code to the block above...) 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 ); }
This appears only in Java 9 (in replacement for sun.misc.Unsafe).
private volatile Thread.State state = NEW; private static final VarHandle ATOMIC_STATE_UPDATER; static { try { MethodHandles.Lookup lookupHandle = MethodHandles.lookup(); ATOMIC_STATE_UPDATER = lookupHandle.findVarHandle( VarHandleExample.class, "state", Thread.State.class ); } catch( ReflectiveOperationException e ) { throw new Error( e ); } } public void update() { ATOMIC_STATE_UPDATER.compareAndSet( this, NEW, RUNNABLE ); }