At work today, I came across the volatile
keyword in Java. Not being very familiar with it, I found this explanation.
Given the detail in which that arti
Volatile Variables are light-weight synchronization. When visibility of latest data among all threads is requirement and atomicity can be compromised , in such situations Volatile Variables must be preferred. Read on volatile variables always return most recent write done by any thread since they are neither cached in registers nor in caches where other processors can not see. Volatile is Lock-Free. I use volatile, when scenario meets criteria as mentioned above.
From oracle documentation page, the need for volatile variable arises to fix memory consistency issues:
Using volatile variables reduces the risk of memory consistency errors, because any write to a volatile variable establishes a happens-before relationship with subsequent reads of that same variable.
This means that changes to a volatile
variable are always visible to other threads. It also means that when a thread reads a volatile variable, it sees not just the latest change to the volatile
, but also the side effects of the code that led up the change.
As explained in Peter Parker
answer, in absence of volatile
modifier, each thread's stack may have their own copy of variable. By making the variable as volatile
, memory consistency issues have been fixed.
Have a look at jenkov tutorial page for better understanding.
Have a look at related SE question for some more details on volatile & use cases to use volatile:
Difference between volatile and synchronized in Java
One practical use case:
You have many threads, which need to print current time in a particular format for example : java.text.SimpleDateFormat("HH-mm-ss")
. Yon can have one class, which converts current time into SimpleDateFormat
and updated the variable for every one second. All other threads can simply use this volatile variable to print current time in log files.
While I see many good Theoretical explanations in the answers mentioned here, I am adding a practical example with an explanation here:
1.
CODE RUN WITHOUT VOLATILE USE
public class VisibilityDemonstration {
private static int sCount = 0;
public static void main(String[] args) {
new Consumer().start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
return;
}
new Producer().start();
}
static class Consumer extends Thread {
@Override
public void run() {
int localValue = -1;
while (true) {
if (localValue != sCount) {
System.out.println("Consumer: detected count change " + sCount);
localValue = sCount;
}
if (sCount >= 5) {
break;
}
}
System.out.println("Consumer: terminating");
}
}
static class Producer extends Thread {
@Override
public void run() {
while (sCount < 5) {
int localValue = sCount;
localValue++;
System.out.println("Producer: incrementing count to " + localValue);
sCount = localValue;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
return;
}
}
System.out.println("Producer: terminating");
}
}
}
In the above code, there are two threads - Producer and Consumer.
The producer thread iterates over the loop 5 times (with a sleep of 1000 milliSecond or 1 Sec) in between. In every iteration, the producer thread increases the value of sCount variable by 1. So, the producer changes the value of sCount from 0 to 5 in all iterations
The consumer thread is in a constant loop and print whenever the value of sCount changes until the value reaches 5 where it ends.
Both the loops are started at the same time. So both the producer and consumer should print the value of sCount 5 times.
OUTPUT
Consumer: detected count change 0
Producer: incrementing count to 1
Producer: incrementing count to 2
Producer: incrementing count to 3
Producer: incrementing count to 4
Producer: incrementing count to 5
Producer: terminating
ANALYSIS
In the above program, when the producer thread updates the value of sCount, it does update the value of the variable in the main memory(memory from where every thread is going to initially read the value of variable). But the consumer thread reads the value of sCount only the first time from this main memory and then caches the value of that variable inside its own memory. So, even if the value of original sCount in main memory has been updated by the producer thread, the consumer thread is reading from its cached value which is not updated. This is called VISIBILITY PROBLEM .
2.
CODE RUN WITH VOLATILE USE
In the above code, replace the line of code where sCount is declared by the following :
private volatile static int sCount = 0;
OUTPUT
Consumer: detected count change 0
Producer: incrementing count to 1
Consumer: detected count change 1
Producer: incrementing count to 2
Consumer: detected count change 2
Producer: incrementing count to 3
Consumer: detected count change 3
Producer: incrementing count to 4
Consumer: detected count change 4
Producer: incrementing count to 5
Consumer: detected count change 5
Consumer: terminating
Producer: terminating
ANALYSIS
When we declare a variable volatile, it means that all reads and all writes to this variable or from this variable will go directly into the main memory. The values of these variables will never be cached.
As the value of the sCount variable is never cached by any thread, the consumer always reads the original value of sCount from the main memory(where it is being updated by producer thread). So, In this case the output is correct where both the threads prints the different values of sCount 5 times.
In this way, the volatile keyword solves the VISIBILITY PROBLEM .
Yes, volatile must be used whenever you want a mutable variable to be accessed by multiple threads. It is not very common usecase because typically you need to perform more than a single atomic operation (e.g. check the variable state before modifying it), in which case you would use a synchronized block instead.
volatile
=> synchronized
[About]
volatile
says for a programmer that the value always will be up to date. The problem is that the value can be saved on different types of hardware memory. For example it can be CPU registers, CPU cache, RAM... СPU registers and CPU cache belong to CPU and can not share a data unlike of RAM which is on the rescue in multithreading envirompment
volatile
keyword says that a variable will be read and written from/to RAM memory directly. It has some computation footprint
Java 5
extended volatile
by supporting happens-before
[About]
A write to a volatile field happens-before every subsequent read of that field.
volatile
keyword does not cure a race condition
situation when several threads can write some values simultaneously. The answer is synchronized
keyword[About]
As a result it safety only when one thread writes and others just read the volatile
value