Java Volatile Keyword Tutorial

In this tutorial we will examine the Java volatile keyword. The Java volatile keyword offfers a weaker from of synchronization.

The purpose of the volatile keyword is to ensure that updates made to a variable declared with volatile are visible and propagted to other threads. When a variable is declared with volatile it tells the Java compiler that the variable should not be cached in a threads working memory such as caches and registers where the value is not visible to other threads.

The volatile keywords ensures that when a volatile variable is written to the updated is always propaged to main memory for other threads to read. It also ensures that the compiler does not reorder operations.

When To Use The Volatile Keyword

First off using the volatile keyword can offer a weaker form of synchronization than using the Java synchronized keyword. The volatile keyword is useful when we have a variable that can act independently from other mutable state declared in an objects variables. The volatile variable can be used when updates to the variable does not depend on its current value, and the variable does not participate in invariants with other variables

In this case the volatile variable is best used as a status flag, such as done, sleep, interruption flag etc. The volatile flag is useful as it tells the Java compiler not to cache and perform optimizations with the variable.

When Not To Use The Volatile Keyword

It is not recommend to use the volatile if the variable if the variable to be marked as volatile has a relationship with other state variables of the object and the correctness of the object depends on this composition, then a volatile variable is probably not the best option in this scenario. Moreover, using multiple volatile variables is not atomic, this is because the interaction with a volatile variable is handled separately then atomically across all volatile variables.

Volatile variables should also not be used for increment operations as this results in three separate operations:

  • Read the value of the variable to thread local memory.
  • Increment the value in local memory.
  • Write the value back to main memory.

In this case it is possible for threads to see different values of the variable and the interleaving of operations can result in unpredictable results. If we need to perform such operations an alternative approach is to use Java Atomic variables.

An Example Using Volatile

As we said volatile is useful when we require a status flag. For example consider the below code that uses a status flag named done that is used to stop a secondary thread when done is set to true.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.stephenenright.tutorials.corejava.concurrency.volatilevariables;

public class VolatileExample {
    static boolean done = false;

    public static void main(String[] args) {
        System.out.println("Program Starting");

        new Thread() {
            public void run() {
                System.out.println("Starting Secondary Thread");
                while (!done) {
                }
                System.out.println("Secondary Thread Terminating");
            }
        }.start();

        try {
            Thread.sleep(700);
        } catch (InterruptedException e) {
            System.out.println("Thread Interrupted :" + e);
        }

        done = true;
        System.out.println("Program Terminating");
    }
}

If we run the above code the program will never terminate, the write on line 24 to set the variable done to true is never seeing by the secondary thread that we started. This is because the main thread stores the update in its local memory and not main memory.

1
2
3
Program Starting
Starting Secondary Thread
Program Terminating

We can fix the problem be declaring the done variable as volatile.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class VolatileExample {

    static volatile boolean done = false;

    public static void main(String[] args) {
        System.out.println("Program Starting");

        new Thread() {
            public void run() {
                System.out.println("Starting Secondary Thread");
                while (!done) {
                }
                System.out.println("Secondary Thread Terminating");
            }
        }.start();

        try {
            Thread.sleep(700);
        } catch (InterruptedException e) {
            System.out.println("Thread Interrupted :" + e);
        }

        done = true;
        System.out.println("Program Terminating");
    }
}

When we run the program again we see the program terminates as expected and we see the following output:

1
2
3
4
Program Starting
Starting Secondary Thread
Program Terminating
Secondary Thread Terminating

When we mark the done variable as volatile the write to set variable done to true, is written to main memory. Therefore, the secondary thread that we start can see this modification, exits out of the while loop and terminates.

Volatile Versus Thread Synchronization

To recap what we discussed in the previous sections, the volatile keyword provides a weaker form of synchronization. What this means is that for a concurrent Java application to perform correctly when working with shared mutable state it needs to ensure the following properties:

  • Mutual Exclusion: only one thread can execute and modify mutable state at a time which can be achieved by synchronization via locking.
  • Memory Visibility: synchronization is not just about locking it also has to do with memory visibility, to ensure that all threads see the most up-to-date values.

The volatile keyword can provide some visibility guarantees when used in the correct scenarios, while synchronized methods and synchronized blocks provide both mutual exclusion and visibility.

Conclusion

In this tutorial, we looked at the volatile keyword in Java. Moreover, we looked at some scenarios where the volatile keyword should and should not be used. Finally we looked at the difference between the volatile keyword and synchronized blocks.