volatile is a keyword in java that is used with variables. By defining a variable as volatile, we say that all read and write operations made to this variable are done from the main memory rather than the local CPU cache (in case of other variables, the read and write operations are done via the local CPU cache for performance).
In a multi threaded application, each thread may cache the variables in its local cache, but the volatile variable will not be cached (even if the variable gets cached in its local stack, the value will be refreshed and will be in sync with the main memory value). And thus, by defining a variable as volatile, we make sure that all the reads to a variable will get the latest value of the variable.
Consider the scenario where three threads - TReader1, TReader2 and TWriter; accessing an integer variable counter. Both reader threads - TReader1 and TReader2 - just read the value of counter and TWriter writes value to it. If counter is not volatile, then, the reader threads read the value from their local cache and the writer thread would also write the value to its local cache, and would, at a later stage write it to the main memory.
Suppose the value of counter was 0 when all threads read the value and placed it in their respective local caches. The subsequent reads of the reader threads will be from their own local caches, and so, will be 0. Now let us assume that the writer thread updates the value of counter to 1. Since counter is not volatile the updated value will be written only to the local cache of the writer thread, and later, will be written to the main memory. However, in the current state, the reader threads would read the value of counter as 0 (from their corresponding local caches). This is not the desired behaviour.
Let us now define the variable counter to be volatile:
Here, the reader and writer threads will not keep the value in their local caches. Therefore, when the value of counter is updated to 1 by TWriter, the value is updated in the main memory itself, and the next read from the reader threads will give the updated value from the main memory. Thus, defining a variable as volatile ensures that all the threads always read the latest value of the variable in the memory.
So is defining a variable as volatile enough to make that variable synchronized?
The answer is NO. volatile is never a substitute for synchronization. Volatility just guarantees the visibility of the variable and NOT atomicity, whereas Synchronization (locking) guarantees both visibility and atomicity.
By visibility we mean that all the threads will get the latest form of the variable. In the above example, as you can see, all the threads get the latest value of counter in the subsequent reads.
As a simple illustration for atomicity, let us again consider the example above. Assume that both TReader1 and TReader2 read the value of volatile variable counter, and say both the reader threads get its value as 1. Now, say both increment this value by one, and then write it. However, you will notice that the value of counter which is written in the main memory is 2 and not 3! This is unlike the case of synchronization, where the value of counter would have been 3 after the update operation by both the threads, because of the locking mechanism.
When to use volatile
As you can clearly see, you can define a variable as volatile only:
We should only use the keyword volatile when it is absolutely necessary to enforce the visibility of the variables. This is because there is a performance hit while using the volatile keyword due to:
This post is written by Jerin Joseph. He is a freelance writer, loves to explore latest features in Java technology.