Monday, November 4, 2013

Currently I can't understand when we should use volatile to declare variable.
I have do some study and searched some materials about it for a long time and know that when a field is declared volatile, the compiler and runtime are put on notice that this variable is shared and that operations on it should not be reordered with other memory operations.
However, I still can't understand in what scenario we should use it. I mean can someone provide any example code which can prove that using "volatile" brings benefit or solve problems compare to without using it?
share|improve this question
5 
volatile (and many other concurrency-related aspects) are very hard to demonstrate, because if you use them wrongly, then they may still appear to work correctly and not show a problem until a very specific condition occurs and leads to a problem. –  Joachim Sauer Apr 28 '11 at 10:05
 
I have tried this myself and produced a test which passes values between threaded using a non-voltile field one billion times successfully, however fails relatively quickly when the same box is loaded. Even timing the performance impact of volatile is very difficult are it depends on lots of factors. –  Peter Lawrey Apr 28 '11 at 10:24

4 Answers

Here is an example of why volatile is necessary. If you remove the keyword volatile, thread 1may never terminate. (When I tested on Java 1.6 Hotspot on Linux, this was indeed the case - your results may vary as the JVM is not obliged to do any caching of variables not marked volatile.)
public class ThreadTest {
  volatile boolean running = true;

  public void test() {
    new Thread(new Runnable() {
      public void run() {
        int counter = 0;
        while (running) {
          counter++;
        }
        System.out.println("Thread 1 finished. Counted up to " + counter);
      }
    }).start();
    new Thread(new Runnable() {
      public void run() {
        // Sleep for a bit so that thread 1 has a chance to start
        try {
          Thread.sleep(100);
        } catch (InterruptedException ignored) { }
        System.out.println("Thread 2 finishing");
        running = false;
      }
    }).start();
  }

  public static void main(String[] args) {
    new ThreadTest().test();
  }
}
share|improve this answer
 
Sorry, I tried to remove "volatile" keyword and run the program for many times, but every time thread 1 can be terminated. I think for the code you provided even without "volatile" thread 1 can always be terminated every time. –  Eric Jiang Apr 28 '11 at 10:40
2 
@Eric: it gives the effect I describe on two different machines running Java 6 JVMs. I guess I should have phrased it differently. It is only guaranteed to terminate if the volatile keyword is present. If it's not present, the JVM is free to cache the value of running, so thread 1 need not terminate. However, it isn't forced to cache the value. –  Simon Nickerson Apr 28 '11 at 11:25
 
Keeping "volatile" present will terminate thread 1 as soon as 'running' is set false in thread 2. But if remove "volatile", thread 1 may won't terminate even after 'running' is set false in thread2, when thread will terminate depends on when JVM update "running" value in thread 1. Do you mean that??? But if "running" has been set 'false' in thread 2, why thread1 can't get the right value??? If so I think JVM behave wrong. –  Eric Jiang Apr 28 '11 at 11:53
1 
The JVM is not behaving wrongly. Without volatile (or synchronization, or something else which forces a 'happens-before' relationship), thread 1 need not see the change made by thread 2. –  Simon Nickerson Apr 28 '11 at 12:02
1 
@Eric: that's exactly the problem: "correct behaviour" is not equivalent to "intuitive behaviour". JVMs are free to cache values (for example in the register of a CPU) if it is read repeatedly and need not read it from main memory each time. Specifying that a variable is volatile disables this caching! –  Joachim Sauer Apr 28 '11 at 14:41
show 3 more comments
The volatile keyword is pretty complex and you need to understand what it does and does not do well before you use it. I recommend reading this language specification section which explains it very well.
They highlight this example:
class Test {
    static volatile int i = 0, j = 0;
    static void one() { i++; j++; }
    static void two() {
        System.out.println("i=" + i + " j=" + j);
    }
}
What this means is that during one() j is never greater than i. However, another Thread runningtwo() might print out a value of j that is much larger than i because let's say two() is running and fetches the value of i. Then one() runs 1000 times. Then the Thread running two finally gets scheduled again and picks up j which is now much larger than the value of i. I think this example perfectly demonstrates the difference between volatile and synchronized - the updates to i and j are volatile which means that the order that they happen in is consistent with the source code. However the two updates happen separately and not atomically so callers may see values that look (to that caller) to be inconsistent.
In a nutshell: Be very careful with volatile!
share|improve this answer

No comments: