Java Volatile is Powerful
May 25, 2008
Author : Pavitar Singh
Java supports two intrinsic concurrency mechanisms “synchronized” and “volatile”. We tend to use synchronized or its newer avatar “locks” from java.util.concurrent most of the times without even checking if volatile or some other option could have been a fit. A careful analysis from concurrency perspective could yield a much smarter and performant solution in many of these scenarios. This analysis would need a good understanding of the properties of each of this mechanism, some of the guarantees that they hold and how it impacts a typical program.
This article takes a look from a Java perspective at some of these semantics and guarantees and does a comparison between synchronized and volatile on some of these parameters. I am also going to go over usages of volatile to build highly performant concurrent programs.
Properties of Concurrent Programs :
A.) Visibility : It determines when actions of one Thread can be seen by the other.
It guarantees whether results of one action can be seen by another action, where both actions can be performed by different Threads.
For Example:
private boolean status;
public void setValue(boolean status){
this.status = status;
}
public boolean getValue(){
return this.status;
}
a.) Thread 1 does setValue
b.) Thread 2 does getValue
Will both Threads see the same value? In order to answer this question we need visibility guarantees which will ensure that value set by
Thread 1 will be visible when Thread 2 does getValue.
B.) Atomicity : It determines whether a set of actions occur indivisibly.
It is also possible that what seems like one action from the language perspective is actually multiple actions in the actual implementation (like incrementing a counter). Atomicity can be enforced on a sequence of actions. Unlike the transactional world it is not about success or failure of the steps, but more about their result being visible together.
C.) Ordering : It determines when actions of one Thread seem to happen out of order to other Threads.
Compilers and Processors do a lot of optimizations which end up reordering the way instructions are executed. But concurrent programs need some
guarantees which restrict some reorderings.
For Example :
void threadOne() {
a = true;
b = true;
}
boolean threadTwo() {
boolean r1 = b; // sees true
boolean r2 = a; // sees false
}
Thread One sets a and b both to true and Thread two can see true for b but false for a.
As compiler or processor may do some reordering like:
void threadOne() {
b = true;
a = true;
}
boolean threadTwo() {
boolean r1 = b; // sees true
boolean r2 = a; // sees false
}
Comparison of synchronized and volatile
We need to see what Java Memory Model has to say about these properties for synchronized and volatile. Guarantees provided by Java Memory Model are centred around Happens Before Relationship( Def: “Two actions can be ordered by a happens-before relationship.
If one action happens before another, then the first is visible to and ordered before the
second”). And according to Java Memory Model :
a.)An unlock on a monitor happens before every subsequent lock on that monitor.
b.)A write to a volatile field happens before every subsequent read of that volatile.
That means volatile and synchronized are going to have same visibility guarantees.
Now question comes about Orderings.For that again we need to look into JMM. If we look into JMM section 6.4 we find following statement :
“It is generally legal to reorder a normal memory access and a following acquire action, or a release action and a following normal memory access. This has been referred to as “roach motel” semantics: variable accesses can be moved into a synchronized block, but cannot, in general, move out.“
And the same section says : “Some operations (e.g., writing a volatile variable, unlocking a monitor, starting a thread) have release semantics.Other operations (e.g., reading a volatile variable,locking a monitor) have acquire semantics”
That means volatile and synchronized have same ordering semantics.
So Volatile doesn’t have Atomicity properties.That means we cannot enforce a sequence of actions to occur atomically with volatiles.
For Example :
volatile int i;
someMethod(){
i++;
}
Here i++ is not a single instructions its basically 3 instructions :
i.) Read i
ii.) Increment i
iii.) Set i
These 3 instructions may not happen atomically.
Thats what make volatile unfit for Counters.
But that still keeps open a lot of other use cases of volatile. Some of these patterns are nicely presented by Brian Goetz here.
I am not going to repeat these patterns, but what I have tried to stress on is the similarity of memory model semantics between volatile and synchronized, other then mutual exclusion (Atomicity is mutual exclusion) and show how these properties has been leveraged in some Java Library Classes to build performant solutions.
We find one of the smartest usages in ConcurrentHashMap which uses volatile properties (as described above) to achieve read (get method) without Locking.
If you will look into the source code you will find that the get method of ConcurrentHashMap is lock free and volatile is used to enforce memory flushes.Now here question comes why in first place we need get method to have any lock.What are guarantees from JMM perspective we are looking for while reading the data. So the answer which should come to our mind is Visiblity, whether changes made in put will be visible in get.As if they are not visible then lot of things can go wrong. So we need Visiblity guarantee in read method. Think more and you will realize other guarantee which we need is ordering. But Why ? When we see visibility its mainly provided by memory barrier being placed at (monitor release/volatile write).But then some variable write instructions can jump over the barrier and they may not be visible in read. So we need ordering guarantee also.
Now if we look into the ConcurrentHashMap source code, we see writes to volatile is happening at the end of put method and same volatile is being read first in get method. This is enforcing Visiblity and Ordering Guarantees which we needed in get method.
count is a volatile variable
V put(K key, int hash, V value, boolean onlyIfAbsent) {
lock();
try {
…
…
…
count = c; // write-volatile
}
return oldValue;
} finally {
unlock();
}
}
As you might have noticed in ConcurrentHashMap, method “put” sets count to a new value which is nothing but a volatile – write which will enforce a memory flush and also enforce ordering and no variable writes can move below it.
V get(Object key, int hash) {
if (count != 0) { // read-volatile
HashEntry e = getFirst(hash);
Now if you will see “get” method, we are reading value of count which is volatile-read.Which means whatever variables will be changed in put method will be visible in get method.
Once again reiterating According to Java Memory Model:
Writing to a volatile field has the same memory effect as a monitor release, and reading from a volatile field has the same memory effect as a monitor acquire.
Effectively, the semantics of volatile have been strengthened substantially, almost to the level of synchronization. Each read or write of a volatile field acts like “half” a synchronization, for purposes of visibility.
Performance Check:
Test Scenario:
1. 8 Threads writing/reading to a ConcurrentHashMap doing 100,000 operations
Ran the Test for ConcurrentHashMap and on a Modified ConcurrentHashMap where i removed count as a volatile and used locks in read method.
As you can see from the Chart that using volatile rather then a lock had significant performance improvements. So volatile if used smartly can be used to build highly performant concurrent application. Thanks to Doug Lea for showing us how volatile can be smartly used.
Another aspect of volatile which i wanted to explain:
A thumb rule which many of us believe is that volatiles make more sense when reads outnumber writes. However, I have always wondered if writes are more, does volatile still give us some benefits, so I thought I will try a test scenario where I vary write percentages and see how volatile performs when Writes outnumber Reads in comparison to synchronized, Locks and Atomic Variables.
Test Scenario:
1. 8 Threads doing 100,000 operations (read and write) on a Volatile,Synchronized,Atomic
As you can see from the Chart that it’s not true that Volatile should be only used when Reads outnumber Writes.
Source code of above tests can be downloaded from here.
Entry Filed under: Concurrency. Tags: Concurrency.
6 Comments Add your own
Leave a Comment
Some HTML allowed:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <pre> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>
Trackback this post | Subscribe to the comments via RSS Feed



1.
pveentjer | May 27, 2008 at 4:19 am
You are forgettin one of the most powerful features of volatile: piggybacking on synchronization. It makes it possible to share objects with visibility problems in a threadsafe manner. Check the JMM topic in “Java Concurrency in Practice” for more info
2.
pavitar | May 27, 2008 at 6:51 am
Hi Peter,
I havent used term piggybacking explicitly but i have tried to explain the same concept. As when volatile write will happen it will execute a memory flush and all writes on other variables before volatile write will also get flushed. And due to ordering guarantees on volatile these other variable (non-volatile) writes wont jump over this volatile write. So thats nothing but piggybacking synchronization as explained by Brian in JCIP.
3.
Ben | May 28, 2008 at 11:14 am
The problem with volatile is that it wasn’t well defined until the JMM and, since so few developers seem to understand proper locking as is, I tend to avoid it. Instead I use the Atomic* implementations, even for a simple boolean flag, where a volatile would work just as well. An atomic is more obvious, better documented, and has nearly the same performance characteristics.
I think its good to inform people of the tricks, but best to advise them to use the library implementations instead. Otherwise, you’ll find more people implement counters using volatile and other such incorrect abuses because they only half understood your post.
4. roScripts - Webmaster&hellip | May 28, 2008 at 11:15 pm
Java Volatile is Powerful « Pit Falls in Java Development…
Java Volatile is Powerful « Pit Falls in Java Development…
5.
Neil Coffey | September 3, 2008 at 8:22 am
Agree with the poster who said that volatile is poorly understood, though I think this is partly because the JMM per se is poorly understood (and that in turn because it is badly explained in the JLS).
In the tests above, it would also be interesting to measure overall throughput, and to look at how this changes with concurrency (number of accessing threads). Also, unless I missed it, you don’t mention what platform you’re running the tests on. The relative speed of processor instructions (and hence of the different locking mechanisms) almost certainly varies.
In case you’re interested, I’ve actually published some related test results looking e.g. at the performance of ConcurrentHashMap,
some timings of comparing locking mechanisms for concurrent array access,
plus some other information on volatile and synchronization that readers may find interesting.
6.
nonothing | February 13, 2009 at 8:40 pm
i’m not sure what you mean by “visibility” … and note, I AM NOT A GURU w/regards to synchronization … however, my understanding is that in synchronized(obj) { … } the current thread has exclusively acquired the “monior” for the “obj” within the {…} block. however, does that imply that all the java compiler will re-read the obj’s fields before using them within that block? will it commit changes to those fields before relinquishing the monitor at the end of the {…} block? apparently so. HOWEVER, what if there is a “wait” within the {…} block? IN THAT CASE the thread surrenders the monitor, and lets another thread have it, until some other thread calls “notify” on obj’s monitor. so, after “wait()”, what if the code now accesses one of obj’s fields? does the compiler re-read that field, if say it had prior been stored in an internal register? I DON’T KNOW. i recently saw some code on the internet for a comp sci class implementing a FIFO queue in which one thread reads, and another thread writes, which made use of wait / notify on the read/write sides, depending as buffer space was available on the write side, and whether data was available on the read side. in that code, volatile fields were used to keep track of the amount of data available, and the amount of writable buffer space available, which i took to mean that within a synchronized block, after a resuming from a “wait”, one can’t assume the compiler will re-read the obj’s field values if they’ve been changed by another thread. BUT I COULD BE WRONG, it could be after resumption from a “wait”, the compiler will refresh all registers that have been filled with obj’s field variables. until i learn otherwise, i’m assuming that values (in this case, object fields) which are altered via a wait/notify mechanism must be declared volatile. assuming this is true, it’s an oversipmlification to say that “synchrnoization” implies visibility, atomicitty, etc. what synchronization does is get exlusive use of a monitor. if you get that exclusive use, and then load VM registers with obj fields, etc., and OTHER threads only alter those fields after acquireing that monitor, then you can be sure that sematncis of visibility, atomicity, and ordering are maintained. i would assume if a VM register has been loaded with a field variable, your code calls “wait”, now you resume from the wait, and you access that field in later code, the compiler is not going to refresh those registers unless the field was marked volatile. i.e. once you resume from your wait, the coimpiler is going to contiue using that stale field data in the register. and that brings up the question, what if you load a local variable with an object field value before your synchroanized(obj) {…} block, and then in your synchornized block, access that field value directly, not the temporary variable. does the compiler reload the vm registers with the field variable? or does it use the value in the VM registers? i would assume the compiler continues to use the stale value. the only reason you’re often safe within synchronized(obj) { … } is that usually the first time you access a field value is within the { … } block, so the compiler is forced to fetch a fresh copy of the data into the registers. I COULD BE WRONG … but it’s frustrating i haven’t seen concurrency issues disucessed ont his level. if i do the following: int k = obj.myInt; synchronized(obj) { int j = obj.myInt; … } will the value of myInt be reloaded, or will the vale in the VM registers be used, to fill j?