When exactly do you use the volatile keyword in Java? [duplicate]
Asked Answered
B

7

92

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?

Bertram answered 15/8, 2010 at 18:36 Comment(4)
possible duplicate of For what is used "volatile" ?, Do you ever use the volatile keyword in Java?, using volatile keyword and many more.Fatuity
stackoverflow.com/questions/106591/… as wellChadwell
Locks offer two primary features: mutual exclusion and visibility. Volatile variables share the visibility features of synchronized, but none of the atomicity features. Read more (by Brian Goetz).Ballman
"none of the atomicity features"...except that volatile declarations on 8 byte primitives long and double make an individual read atomic or an individual write atomic. This is atomicity on a small scale. You need synchronized blocks to have large scale atomicity.Burkle
C
117

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) at a time
         * "atomically", in the sense that other threads can not 
         * observe the intermediate state between (1) and (2).
         * Therefore, the counter will be accurate.
         */
        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 operation is a single operation, so you 
        // do not need compound atomicity
        temperature = temp;
    }

    public static void main(String[] args) throws Exception{
        while(true){
           Thread.sleep(2000);
           System.out.println("Today's temperature is "+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. However, you should not risk not using volatile when necessary, since it can lead to nasty bugs (caused by in-completely constructed objects etc.).

If you put volatile keyword on something that doesn't need volatile, it won't affect your code's correctness (i.e. the behaviour will not change). In terms of performance, it will depend on the JVM implementation. In theory you might get a tiny performance degradation because the compiler can't do reordering optimisations, have to invalidate CPU cache etc., but then again the compiler could prove that your field cannot ever be accessed by multiple threads and remove the effect of volatile keyword completely and compile it to identical instructions.

EDIT:
Response to this comment:

Ok, but why can't we make todaysTemperature synchronized and create a synchronized getter for temperature?

You can and it will behave correctly. Anything that you can with volatile can be done with synchronized, but not vice versa. There are two reasons you might prefer volatile if you can:

  1. Less bug prone: This depends on the context, but in many cases using volatile is less prone to concurrency bugs, like blocking while holding the lock, deadlocks etc.
  2. More performant: In most JVM implementations, volatile can have significantly higher throughput and better latency. However in most applications the difference is too small to matter.
Cathern answered 15/8, 2010 at 18:56 Comment(9)
I've seen this question a lot, and this is the first answer that makes perfect sense to me. Thank you.Tm
Ok, but why can't we make todaysTemperature synchronized and create a synchronized getter for temperature?Bridget
@SemyonDanilov: Added an answer at the bottom. HTH.Cathern
To me it's still not clear how the synchronized getter will be helpful here? Without using volatile we still have no guarantees about thread-local cache.Peacock
@St.Antario: Guarantees provided by synchronized is a superset of what volatile provides, so it would be redundant to use volatile in addition to synchronized.Cathern
Yes, I've already asked about it here.Peacock
Further solidifying how this works: it is a compile error to define a field that is both volatile and final. It doesn't make any sense since a final variable cannot be reassigned.Rejuvenate
@EnnoShioji: I searched for atomic compound statement, but still fail to understand the concept. Can you please explain what you mean by atomic compound in this context?Kendakendal
Akshayraj Kore, when he says "compound atomicity" he means multiple operations that need to be, as a whole, atomic. For example all the code you put in a synchronized method or synchronized block. Another example is i++ because it is 3 operations: read, increment, write. Placing i++ in a synchronized block makes the 3 operations, as a whole, atomicBurkle
S
15

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.

Solvolysis answered 15/8, 2010 at 18:38 Comment(0)
S
7

volatile keyword guarantees that value of the volatile variable will always be read from main memory and not from Thread's local cache.

From java concurrency tutorial :

Using volatile variables reduces the risk of memory consistency errors, because any write to a volatile variable establishes a happens-before relationship with subsequent reads of that same variable

This means that changes to a volatile variable are always visible to other threads. It also means that when a thread reads a volatile variable, it sees not just the latest change to the volatile, but also the side effects of the code that led up the change.

Regarding your query:

How do I know when I should mark a variable volatile? What are the rules of thumb when figuring out what variables should be volatile in multithreaded code?

If you feel that all reader threads always get latest value of a variable, you have to mark variable as volatile

If you have one writer thread to modify the value of variable and multiple reader threads to read the value of variable, volatile modifier guarantees memory consistency.

If you have multiple threads to write and read variables, volatile modifier alone does not guaranty memory consistency. You have to synchronize the code or use high level concurrency constructs like Locks, Concurrent Collections, Atomic variables etc.

Related SE questions/articles:

Volatile variable explanation in Java docs

Difference between volatile and synchronized in Java

javarevisited article

Snowplow answered 5/9, 2016 at 16:43 Comment(0)
F
6

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.

Frazer answered 15/8, 2010 at 19:12 Comment(2)
So I think that the "immutable" piece of this is somewhat questionable... see my answer over here: stackoverflow.com/questions/3964317/… and the JSR-133 FAQ, item 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...Recess
@Recess 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.Ivett
J
3

Actually disagree with the example given in the top voted answer, to my knowledge it does NOT properly illustrate volatile semantics as per the Java memory model. Volatile has way more complex semantics.

In the example provided, the main thread could continue to print "Today's temperature is 0" forever even if there is another thread running that is supposed to update the temperature if that other thread never gets scheduled.

A better way to illustrate volatile semantics is with 2 variables.

For simplicity's sake, we will assume that the only way to update the two variables is through the method "setTemperatures".

For simplicity's sake, we will assume that only 2 threads are running, main thread and thread 2.

//volatile variable
private static volatile int temperature; 
//any other variable, could be volatile or not volatile doesnt matter.
private static int yesterdaysTemperature
//Called by other thread(s)
public static void setTemperatures(int temp, int yestemp){
    //thread updates yesterday's temperature
    yesterdaysTemperature = yestemp;
    //thread updates today's temperature. 
    //This instruction can NOT be moved above the previous instruction for optimization.
    temperature = temp;
   }

the last two assignment instructions can NOT be reordered for optimization purposes by either the compiler, runtime or the hardware.

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

Once the main thread reads the volatile variable temperature (in the process of printing it),

1) There is a guarantee that it will see the most recently written value of this volatile variable regardless of how many threads are writing to it, regardless of which method they are updating it in, synchronized or not.

2) If the system.out statement in the main thread runs, after the time instant at which thread 2 has run the statement temperature = temp, both yesterday's temperature and todays temperature will be guaranteed to print the values set in them by thread 2 when it ran the statement temperature=temp.

This situation gets a LOT more complex if a) Multiple threads are running and b) There are other methods than just the setTemperatures method that can update the variable yesterday's temperature and todays temperature that are actively being called by these other threads. I think it would take a decent size article to analyze the implications based on how the Java Memory Model describes the volatile semantics.

In short, attempting to just use volatile for synchronization is extremely risky, and you would be better off sticking to synchronizing your methods.

Jody answered 14/1, 2016 at 16:39 Comment(1)
Your example might also serve to explain where using synchronized might be better. Those print statements could run while the other thread had executed "yesterdaysTemperature = yestemp" but not yet executed "temperature = temp", could it not?Comminute
M
2

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."

Mozarab answered 15/8, 2010 at 18:38 Comment(0)
C
2

voltalie Means Keep changing value.The value of this variable will never be cached thread-locally: all reads and writes will go straight to "main memory".In other words Java compiler and Thread that do not cache value of this variable and always read it from main memory.

Configuration answered 11/4, 2018 at 5:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.