帐前卒专栏

Without software, we are nothing.

What Does Volatile Do?

copy from http://www.javaperformancetuning.com/news/qotm030.shtml

What does

1
volatile

do?

This is probably best explained by comparing the effects that

1
volatile

and

1
synchronized

have on a method.

1
volatile

is a field modifier, while

1
synchronized

modifies code blocks and methods. So we can specify three variations of a simple accessor using those two keywords:

1
2
3
int i1;              int geti1() {return i1;}
volatile int i2;              int geti2() {return i2;}
         int i3; synchronized int geti3() {return i3;}
1
geti1()

accesses the value currently stored in

1
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

1
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

1
i1

, for thread1 to have a value of 2 for

1
i1

and for thread2 to have a value of 3 for

1
i1

if thread1 and thread2 have both updated

1
i1

but those updated value has not yet been propagated to “main” memory or other threads.

On the other hand,

1
geti2()

effectively accesses the value of

1
i2

from “main” memory. A

1
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

1
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

1
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

1
volatile

already synchronizes data across threads, what is

1
synchronized

for? Well there are two differences. Firstly

1
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

1
synchronized

. But

1
synchronized

also synchronizes memory. In fact

1
synchronized

synchronizes the whole of thread memory with “main” memory. So executing

1
geti3()

does the following:

  1. The thread acquires the lock on the monitor for object
    1
    
    this
    (assuming the monitor is unlocked, otherwise the thread waits until the monitor is unlocked).
  2. The thread memory flushes all its variables, i.e. it has all of its variables effectively read from “main” memory (JVMs can use dirty sets to optimize this so that only “dirty” variables are flushed, but conceptually this is the same. See section 17.9 of the Java language specification).
  3. The code block is executed (in this case setting the return value to the current value of
    1
    
    i3
    , which may have just been reset from “main” memory).
  4. (Any changes to variables would normally now be written out to “main” memory, but for
    1
    
    geti3()
    we have no changes.)
  5. The thread releases the lock on the monitor for object
    1
    
    this
    .

So where

1
volatile

only synchronizes the value of one variable between thread memory and “main” memory,

1
synchronized

synchronizes the value of all variables between thread memory and “main” memory, and locks and releases a monitor to boot. Clearly

1
synchronized

is likely to have more overhead than

1
volatile

.

Comments