Java Concurrency - Volatile Keyword
In this tutorial, we are going to learn the volatile
variables in Java with examples. The volatile
keyword is a light-weight synchronization mechanism that provides memory visibility and prevents the compiler reordering code. In short, if a variable is declared as volatile
, all reads are read from the main memory and return the most updated write by any thread. A Typical usage of volatile
variables is to check a flag to determine when to exit a loop. Let's go through some examples.
Shut Down Server #
We pretend there is a server running in background, another thread can shut it down by modifying the shutdown
to true
.
Without volatile keyword:
public class VolatileExample extends Thread {
boolean shutdown = false;
public void run() {
while (!shutdown) {
}
}
public static void main(String[] args) throws InterruptedException {
VolatileExample t = new VolatileExample();
t.start();
Thread.sleep(2000);
t.shutdown = true;
t.join();
}
}
As expected, this example will run indefinitely because the thread t
sees the cached value of the field shutdown
even the main thread updates it. To prevent this happens, add the volatile
modifier to shutdown
variable:
boolean volatile shutdown = false;
Now, your application will terminate after two seconds.
Note: It is likely you want to print something inside the run()
method block and hope the application print the message forever, But in fact the application also stops after two seconds.
public void run() {
while (!shutdown) {
System.out.println("Server is running!");
}
}
The reason is that the System.out.println
method is synchronized and so the thread t
are actually getting updated (synchronized) every time.
Why volatile is needed in double-checked locking? #
In my previous article, I have talked about that the race condition can be avoided by using the Double-Checked Locking
. But did you know why the volatile
keyword is used? This is because a non-fully initialized object may being used when another thread sees that assignment and the volatile
keyword prevent that. See this page for more information about double-checked locking. However, so far I cannot find an example of non-fully initialized object in online so please let me know if you find it!
Happens-Before Guarantee #
Since compiler can reorder our code for optimizing the performance, this may produce some unexpected behavior. Therefore, the Java volatile
keyword provides a happens-before
guarantee. From this tutorial, we can see that there are two types of happens-before guarantees:
-
Writes to volatile variables
means a write to a variable before a write avolatile
variable is guaranteed to happened before the write to that volatile variable -
Reads of volatile variables
means a read to avolatile
variable always happens before any subsequent reads of variables
Writes to Example:
this.a = a; // this.a is a non volatile variable
this.b = b; // this.b is a non volatile variable
this.c = c; // this.c is a volatile variable
The only possible write orders are (a, b, c) or (b, a, c). c
should be the last.
Reads from Example:
int a = this.a; // this.a is a volatile variable
int b = this.b; // this.b is a non volatile variable
int c = this.c; // this.c is a non volatile variable
The only possible read orders are (a, b, c) or (a, c, b). a
should be the first.
- Previous: Java Concurrency - Race Condition
- Next: Java Reporting - PDFBox