|
|
|
Back to newsletter 030 contents
What does volatile do?
This is probably best explained by comparing the effects that volatile and
synchronized have on a method. volatile is a field
modifier, while synchronized modifies code blocks and methods. So
we can specify three variations of a simple accessor using those two keywords:
int i1; int geti1() {return i1;}
volatile int i2; int geti2() {return i2;}
int i3; synchronized int geti3() {return i3;}
geti1() accesses the value currently stored in i1 in
the current thread. Threads can have local copies of variables, and the data
does not have to be the same as the data held in other threads. In particular,
another thread may have updated i1 in it's thread, but the value
in the current thread could be different from that updated value. In fact Java
has the idea of a "main" memory, and this is the memory that holds the current
"correct" value for variables. Threads can have their own copy of data for
variables, and the thread copy can be different from the "main" memory. So
in fact, it is possible for the "main" memory to have a value of 1 for i1,
for thread1 to have a value of 2 for i1 and for thread2 to have a value of
3 for i1 if thread1 and thread2 have both updated i1 but
those updated value has not yet been propagated to "main" memory or other threads.
On the other hand, geti2() effectively accesses the value of i2
from "main" memory. A volatile variable is not allowed to have a local copy
of a variable that is different from the value currently held in "main" memory. Effectively,
a variable declared volatile must have it's data synchronized across all threads,
so that whenever you access or update the variable in any thread, all other threads
immediately see the same value. Of course, it is likely that volatile
variables have a higher access and update overhead than "plain" variables, since the
reason threads can have their own copy of data is for better efficiency.
Well if volatile already synchronizes data across threads, what is
synchronized for? Well there are two differences. Firstly
synchronized obtains and releases locks on monitors which can force
only one thread at a time to execute a code block, if both threads use the same
monitor (effectively the same object lock). That's the fairly well known aspect to
synchronized. But synchronized also synchronizes memory.
In fact synchronized synchronizes the whole of thread memory with
"main" memory. So executing geti3() does the following:
this
(assuming the monitor is unlocked, otherwise the thread waits until the monitor is unlocked).
i3, which may have just been reset from "main" memory).
geti3() we have no changes.)
this.
So where volatile only synchronizes the value of one variable between
thread memory and "main" memory, synchronized synchronizes the value
of all variables between thread memory and "main" memory, and locks and releases a
monitor to boot. Clearly synchronized is likely to have more overhead
than volatile.
The JavaPerformanceTuning.com team
Back to newsletter 030 contents