Volatile is a mechanism for lighter weight synchronization where memory visibility of the protected state is guaranteed to all consecutive threads.
A write to volatile variable not only flush changes of the volatile variable but all the non volatile variables changed before write to volatile. Thus a simple flag of volatile type can serve the memory visibility guarantee of all the other variables changed before. The following figure explain it in entirety.
Non-atomic treatment of long and double
For the purposes of the Java programming language memory model, a single write to a non-volatile long or double value is treated as two separate writes: one to each 32-bit half. This can result in a situation where a thread sees the first 32 bits of a 64-bit value from one write, and the second 32 bits from another write.
Writes and reads of volatile long and double values are always atomic.
Writes to and reads of references are always atomic, regardless of whether they are implemented as 32-bit or 64-bit values.
It is safe to perform read-modify-write operations on a shared volatile variable as long as you ensure that the volatile variable is only written from single thread.
volatile variables are liable to get into race conditions because atomicity is required to solve race condition