Java Memory model defines the possible rules for threads and the expected behavior of multi-threaded programs so that programmers can design their programs accordingly. JSR-133 describes the semantics of threads, locks, volatile variables and data races.
Volatile variables are treated different from other variables. When you mark a variable as volatile, this warns the compiler to get fresh copies of the variable rather than caching the variable in the registers.
Volatile variables can be used to store shared variables at a lower cost than that of synchronization, but they have limitations. While writes to volatile variables are guaranteed to be immediately visible to other threads (because JVM does not allow threads to cache volatile variables), there is no way to render a read-modify-write sequence of operations atomic, meaning, for example, that a volatile variable cannot be used to reliably implement a mutex (mutual exclusion lock) or a counter.
Let's demonstrate this with a counter example. In the example a volatile counter variable will be incremented by multiple threads simultaneously. Below is the main class that holds the volatile variable and starts the threads.
Here is our example thread source code:
I used jdk1.5.0_12 to run this application. I used 10 threads, each increments the variable 10000 times. The result is as expected. Volatile keyword does not guarantie mutual exclusion. Here is the result:
As a result: Volatile variables are best for use when there is only one thread that makes writes (updates volatile variable) and N threads that make reads. Reader threads get the most recent value of the volatile parameter when they perform a read.
Expected counter value : 100000
Result : 85751