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?
Yes, volatile must be used whenever you want a mutable variable to be accessed by multiple threads. It is not very common usecase because typically you need to perform more than a single atomic operation (e.g. check the variable state before modifying it), in which case you would use a synchronized block instead.
The volatile keyword is intended to prevent the compiler from applying any optimizations on objects that can change in ways that cannot be determined by the compiler. Objects declared as volatile are omitted from optimization because their values can be changed by code outside the scope of current code at any time.
The volatile modifier is used to let the JVM understand that a thread accessing the variable should always merge its own personal copy of the variable with the original in the memory. Accessing a volatile variable synchronizes all the cached copy of the variables in the main memory.
The Java volatile keyword is intended to address variable visibility problems. By declaring the counter variable volatile all writes to the counter variable will be written back to main memory immediately. Also, all reads of the counter variable will be read directly from main memory.
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:
volatile
is less prone to concurrency bugs, like blocking while holding the lock, deadlocks etc.volatile
can have significantly higher throughput and better latency. However in most applications the difference is too small to matter. If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With