Volatile Keyword Java Example
In this tutorial, we will discuss the volatile keyword in Java. When a field is declared as volatile
, then, the Java Memory Model ensures that all threads will “see” the same consistent value.
In Java, global ordering is imposed on the reading and write operations concerning a volatile
variable. A thread that access a volatile field, will first read its current value from the main memory, instead of using a potential cached value. A write operation to a volatile
variable establishes a happens-before relationship with all subsequent reads of that volatile
variable. Therefore, any change to a volatile
variable is always visible to other threads.
1. The volatile keyword in Java
In the following example, we demonstrate a sample example of how to use a volatile
variable.
VolatileData.java
01 02 03 04 05 06 07 08 09 10 11 12 | public class VolatileData { private volatile int counter = 0 ; public int getCounter() { return counter; } public void increaseCounter() { ++counter; } } |
Initially, we declare a new class, called VolatileData
that has a private integer field, declared as volatile
. The class supports two methods, getCounter
and increaseCounter
, which return the current value and increase the current value by one, respectively.
VolatileThread.java
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 | public class VolatileThread extends Thread { private final VolatileData data; public VolatileThread(VolatileData data) { this .data = data; } @Override public void run() { int oldValue = data.getCounter(); System.out.println( "[Thread " + Thread.currentThread().getId() + "]: Old value = " + oldValue); data.increaseCounter(); int newValue = data.getCounter(); System.out.println( "[Thread " + Thread.currentThread().getId() + "]: New value = " + newValue); } } |
In addition, we declare a new class, called VolatileThread
, which receives an instance of the VolatileClass
in its constructor. Then, during its execution, the thread prints the current value of the volatile
variable, increases it by one and finally, prints the updated value of the volatile
variable.
VolatileMain.java
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 | public class VolatileMain { private final static int TOTAL_THREADS = 2 ; public static void main(String[] args) throws InterruptedException { VolatileData volatileData = new VolatileData(); Thread[] threads = new Thread[TOTAL_THREADS]; for ( int i = 0 ; i < TOTAL_THREADS; ++i) threads[i] = new VolatileThread(volatileData); //Start all reader threads. for ( int i = 0 ; i < TOTAL_THREADS; ++i) threads[i].start(); //Wait for all threads to terminate. for ( int i = 0 ; i < TOTAL_THREADS; ++i) threads[i].join(); } } |
Inside the main
method we start two threads that have access to the same volatile
variable. A sample execution is shown below:
1 2 3 4 | [Thread 10]: Old value = 0 [Thread 11]: Old value = 0 [Thread 10]: New value = 1 [Thread 11]: New value = 2 |
As we observe, initially, both threads print the same value. The second thread accesses and prints the latest value of the volatile
variable, after both increaseCounter()
operations have been applied.
2. Need for volatile
The Java programming language allows threads to access shared variables. As a rule, to ensure that shared variables are consistently and reliably updated, a thread should ensure that it has exclusive use of such variables by obtaining a lock that, conventionally, enforces mutual exclusion for those shared variables.
A field may be declared volatile, in which case the Java Memory Model ensures that all threads see a consistent value for the variable. One common example of using volatile
is to use a volatile
boolean variable as a flag to terminate a thread. If you’ve started a thread, and you want to be able to safely interrupt it from a different thread, you can have the thread periodically check a flag.
3. When to use Volatile
Declaring a variable volatile
thus guarantees the visibility for other threads of writes to that variable. In Java, we can not have synchronized
variable. Using synchronized
keyword with a variable is illegal and will result in compilation error. Instead of using the synchronized
variable in Java, you can use the java volatile
variable, which will instruct JVM threads to read the value of volatile
variable from main memory and don’t cache it locally.
If a variable is not shared between multiple threads then there is no need to use the volatile
keyword.
4. Code
In this section, we will see how volatile
works. Let’s assume we have 3 cores in the systems. Each core will have its own L1 and L2 cache. These cores will communicate with RAM via L3 cache and the bus.
Now if the two threads run in different cores there is a possibility that the results are inconsistent as the threads can cache the results in there respective cache.
Let’s create a class and define a static class variable:
private static int value = 0;
Now we will define two threads one for reading the value and the other for writing it. In the Reader class, we will first create a local variable and will initialize its value to the global value. Then in a loop, we will check if the local value is the same as the global one, if not then we will print the new global value.
int local_value = value; while (local_value < 10) { if (local_value != value) { System.out.println(format("Global value has changed to: %s", value)); local_value = value; } }
Below is the writer thread:
int local_value = value; while (value < 10) { System.out.println(format("Incrementing global value to %s", local_value + 1)); value = ++local_value; try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } }
When we run this we will see result as below:
Incrementing global value to 1 Incrementing global value to 2 Incrementing global value to 3 Incrementing global value to 4 Incrementing global value to 5 Incrementing global value to 6 Incrementing global value to 7 Incrementing global value to 8 Incrementing global value to 9 Incrementing global value to 10
Now if we make the global variable volatile
Incrementing global value to 1 Global value has changed to: 1 Incrementing global value to 2 Global value has changed to: 2 Incrementing global value to 3 Global value has changed to: 3 Incrementing global value to 4 Global value has changed to: 4 Incrementing global value to 5 Global value has changed to: 5 Incrementing global value to 6 Global value has changed to: 6 Incrementing global value to 7 Global value has changed to: 7 Incrementing global value to 8 Global value has changed to: 8 Incrementing global value to 9 Global value has changed to: 9 Incrementing global value to 10 Global value has changed to: 10
When we made the variable volatile
it is read from the main memory and is not cached via individual thread.
VolatileExample.java
package com.javacodegeeks; import static java.lang.String.format; public class VolatileExample { private volatile static int value = 0; public static void main(String[] args) { new DataReader().start(); new DataWriter().start(); } static class DataReader extends Thread { @Override public void run() { int local_value = value; while (local_value < 10) { if (local_value != value) { System.out.println(format("Global value has changed to: %s", value)); local_value = value; } } } } static class DataWriter extends Thread { @Override public void run() { int local_value = value; while (value < 10) { System.out.println(format("Incrementing global value to %s", local_value + 1)); value = ++local_value; try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } } }
5. More about the volatile keyword
While using the volatile
keyword in your application’s code, you must be aware of the following:
- The
volatile
keyword does not eliminate the need of synchronization among atomic actions, because memory consistency errors are still possible. - The usage of atomic variables is more efficient compared to the access through synchronized code, but it requires an extra effort by the programmer, in order for memory inconsistency errors to be avoided.
- The
volatile
keyword is not a replacement of a synchronized block or method.
6. Download the Eclipse Project
You can download the full source code of this example here: Volatile Keyword Java Example
Last updated on Jun. 30th, 2020