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

3 Tips for Volatile Fields in Java

DZone's Guide to

3 Tips for Volatile Fields in Java

When should you use volatile fields in your multi-threaded Java projects? Here are three tips to help, including one specific for Java 9 adopters.

· Java Zone ·
Free Resource

Get the Edge with a Professional Java IDE. 30-day free trial.

Volatile fields are built-in mechanisms to write multi-threaded Java.

Volatile variables are not cached in registers or in caches where they are hidden from other processors, so a read of a volatile variable always returns the most recent write by any thread. ... The visibility effects of volatile variables extend beyond the value of the volatile variable itself. When thread A writes to a volatile variable and subsequently thread B reads that same variable, the values of all variables that were visible to A prior to writing to the variable become visible to B after reading the volatile variable.
Java Concurrency in Practice - Brian Goetz, et al.

In the following article, I collected three tips on when and how to use volatile fields in practice.

Use Volatile Fields When Writes Do Not Depend on Its Current Value

An example is a flag to stop a worker thread from another thread:

public class WorkerThread extends Thread {
    private volatile boolean isRunning = true;
    @Override
    public void run() {
        while (isRunning) {
            // execute a task
        }
    }
    public void stopWorker() {
        isRunning = false;
    }
}


The WorkerThread executes its tasks in a while loop, line 5. It checks the volatile field isRunning in each iteration and stops processing if the field is false. This allows other threads to stop the WorkerThread by calling the method stopWorker, which sets the value of the field to false. Since a thread can call the method stopWorker even if the WorkerThread is already stopped, the write to the field can be executed independently of its current value.

By declaring the field volatile, we make sure that the WorkerThread sees the update done in another Thread and does not run forever.

Use Volatile Fields for Reading and Locks for Writing

java.util.concurrent.CopyOnWriteArrayList's get and set methods are an example of this tip:

public class CopyOnWriteArrayList < E >
    implements List < E > , RandomAccess, Cloneable, java.io.Serializable {
        private transient volatile Object[] array;
        final Object[] getArray() {
            return array;
        }
        final void setArray(Object[] a) {
            array = a;
        }
        private E get(Object[] a, int index) {
            return (E) a[index];
        }
        public E get(int index) {
            return get(getArray(), index);
        }
        public E set(int index, E element) {
            final ReentrantLock lock = this.lock;
            lock.lock();
            try {
                Object[] elements = getArray();
                E oldValue = get(elements, index);
                if (oldValue != element) {
                    int len = elements.length;
                    Object[] newElements = Arrays.copyOf(elements, len);
                    newElements[index] = element;
                    setArray(newElements);
                } else {
                    // Not quite a no-op; ensures volatile write semantics
                    setArray(elements);
                }
                return oldValue;
            } finally {
                lock.unlock();
            }
        }
        // Other fields and methods omitted
    }


The get method, line 13, simply reads the volatile field array and returns the value at the position index. Writing uses a lock to ensure that only one thread can modify the array at a given time. Line 18 acquires the lock and line 33 releases the lock. Writing requires copying the array when an element is changed, line 24, so that the reading threads do not see an inconsistent state. The writing thread then updates the array, line 25, and sets the new array to the volatile field array, line 26.

Using this tip only writes block writes. Compare this to using synchronized set and get methods, where each operation blocks all other operations. Or java.util.concurrent.locks.ReentrantReadWriteLock, where too many readers can lead to a starvation of writers. This is especially a problem for older JDKs, see the comment from Akhil Mittal below.

Use With JDK 9's VarHandle for Atomic Operations

All modern CPUs provide instructions to atomically compare and set or increment and get values. Those operations are used internally by the JVM to implement synchronized locks. Prior to JDK 1.9, they were available for Java applications only through classes in the java.util.concurrent.atomic package or by using the private java API sun.misc.Unsafe. With the new JDK 9 VarHandle, it is now possible to execute such operations directly on volatile fields. The following shows the AtomicBoolean compareAndSet method implemented using VarHandles:

public class AtomicBoolean implements java.io.Serializable {
    private static final VarHandle VALUE;
    static {
        try {
            MethodHandles.Lookup l = MethodHandles.lookup();
            VALUE = l.findVarHandle(AtomicBoolean.class, "value", int.class);
        } catch (ReflectiveOperationException e) {
            throw new Error(e);
        }
    }
    private volatile int value;
    public final boolean compareAndSet(boolean expectedValue, boolean newValue) {
        return VALUE.compareAndSet(this,
            (expectedValue ? 1 : 0),
            (newValue ? 1 : 0));
    }
    // Other fields and methods omitted
}


The VarHandle works similarly to the class java.lang.reflect.Field. You need to look up a VarHandle from the class that contains the field using the name of the field, line 6. To execute a compareAndSet operation on the field, we need to call the VarHandle with the object of the field, the expected and the new value, line 13.

Conclusion

You can use volatile fields if the writes do not depend on the current value, as in tip one. Or if you can make sure that only one thread at a time can update the field, as in tips two and three. I think that those three tips cover the more common ways to use volatile fields. Read here about a more exotic way to use volatile fields to implement a concurrent queue. And if you want to test whether your application is thread-safe, try vmlens for free.

I would be glad to hear from you about other ways to use volatile fields to achieve thread-safety.

Get the Java IDE that understands code & makes developing enjoyable. Level up your code with IntelliJ IDEA. Download the free trial.

Topics:
java ,volatile ,thread safe ,fields ,tutorial ,multi-threading

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

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

{{ parent.tldr }}

{{ parent.urlSource.name }}