Java doesn't really have a concept of "volatile memory". Instead, the volatile
keyword changes the guarantees the JVM makes about when and how a field will be written and read. Wikipedia has a decent breakdown of what Java (and other languages) mean by volatile
.
Very roughly speaking, a volatile
field is equivalent to a field that is always read-from and written-to like so:
// read
T local;
synchronized {
local = field;
}
// ... do something with local
// write
synchronized {
field = local;
}
In other words, reads and writes of volatile
fields are atomic, and always visible to other threads. For simple concurrency operations this is sufficient, but you may well still need explicit synchronization to ensure compound operations are handled correctly. The advantage of volatile
is that it's smaller (affecting exactly one field) and so can be handled more efficiently than a synchronized code block.
You'll notice from my psuedo-translation that any modifications or mutations to the field are not synchronized
, meaning there is no memory barrier or happens-before relationship being imposed on anything you might do with the retrieved object. The only thing volatile
provides is thread-safe field reads and writes. This is a feature because it's much more efficient than a synchronized
block when all you need is to update a field.
I would strongly encourage you to read Java Concurrency in Practice if you haven't before; it provides an excellent overview of everything you need to know about concurrency in Java, including the difference between volatile
and synchronized
.
Obviously, this doesn't happen, or else I would have encountered such a problem during my career. I never did.
Note that this is a fallacious line of reasoning. It is perfectly possible for you to do something wrong yet never be affected by it or simply not notice its effects. For instance over-synchronized code (like Vector
) will work correctly but run much slower than alternative solutions.