views:

157

answers:

4

I have read "When to use 'volatile' in Java?" but I'm still confused. How do I know when I should mark a variable volatile? What if I get it wrong, either omitting a volatile on something that needs it or putting volatile on something that doesn't? What are the rules of thumb when figuring out what variables should be volatile in multithreaded code?

A: 

http://mindprod.com/jgloss/volatile.html

"The volatile keyword is used on variables that may be modified simultaneously by other threads."

"Since other threads cannot see local variables, there is never any need to mark local variables volatile. You need synchronized to co-ordinate changes to variables from different threads, but often volatile will do just to look at them."

Molske
+2  A: 

Volatile is most useful in lock-free algorithms. You mark the variable holding shared data as volatile when you are not using locking to access that variable and you want changes made by one thread to be visible in another, or you want to create a "happens-after" relation to ensure that computation is not re-ordered, again, to ensure changes become visible at the appropriate time.

The JMM Cookbook describes which operations can be re-ordered and which cannot.

mdma
+2  A: 

Since others have already provided formal answers, I'll try to provide an intuitive answer:

You basically use it when you want to let a member variable be accessed by multiple threads but do not need compound atomicity (not sure if this is the right terminology).

class BadExample {
    private volatile int counter;

    public void hit(){
        /* This operation is in fact two operations:
         * 1) int tmp = this.counter;
         * 2) this.counter = tmp + 1;
         * and is thus broken (counter becomes fewer
         * than the accurate amount).
         */
        counter++;
    }
}

the above is a bad example, because you need compound atomicity

 class BadExampleFixed {
    private int counter;

    public synchronized void hit(){
        /*
         * Only one thread performs action (1), (2)
         * "atomically", in the sense that other threads can not 
         * observe the intermediate state between (1) and (2).
         */
        counter++;
    }
}

Now to a valid example:

 class GoodExample {
    private static volatile int temperature;

    //Called by some other thread than main
    public static void todaysTemperature(int temp){
        this.temperature = temp
    }

    public static void main(String[] args) throws Exception{
        while(true){
           Thread.sleep(2000);
           System.out.println("Today's temperature is "+this.temperature);
        }
    }
}

Now, why can't you just use private static int temperature? In fact you can (in the sense that that your program won't blow up or something), but the change to temperature by the other thread may or may not be "visible" to the main thread.

Basically this means that it is even possible that your app. keeps writing Today's temperature is 0 forever if you don't use volatile (in practice, the value tends to become eventually visible, but you should not risk not using volatile when necessary, since it can lead to nasty bugs (caused by in-completely constructed objects etc.).

Finally, a general tip for multi-threaded programming.. Have as few as possible mutable shared state. Always strive to use immutable datastructure, or not to share the state. In the few cases you have to, prefer java.util.concurrent libraries over primitives like volatile, synchronized.

Enno Shioji
+2  A: 

The volatile can also be used to safely publish immutable objects in a multi-threaded Environment.

Declaring a field like public volatile ImmutableObject foo secures that all threads always see the currently available instance reference.

See Java Concurrency in Practice for more on that topic.

Johannes Wachter
@Johannes Wachter: So I think that the "immutable" piece of this is somewhat questionable... see my answer over here: http://stackoverflow.com/questions/3964317/memory-barriers-and-coding-style-over-a-java-vm and the JSR-133 FAQ, item http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#volatile . I think a more accurate statement is that you can safely publish objects that don't require other synchronization... I may not have my head around this properly, but as long as a volatile write happens, normal writes in the same thread which precede would be visible to any thread reading...
andersoj
@andersoj is correct, volatility is transitive. a read of a.b is volatile is the read of a is volatile. a write to a.b happens-before a write to a if it precedes it in program order. Therefore volatile can be used to safely publish a mutable (otherwise non-threadsafe) object. I don't think this is a particularly good idea mind, and always preach immutable objects wherever possible, but it is still an important point.
Jed Wesley-Smith