Here is a very good example illustrating the issue the prohibition on reordering is aimed to address (taken from here):
class VolatileExample {
int x = 0;
volatile boolean v = false;
public void writer() {
x = 42;
v = true;
}
public void reader() {
if (v == true) {
//uses x - guaranteed to see 42.
}
}
}
In this example, v is volatile, but x is not. If writer and reader are executed concurrently and the reader sees v set to true, x is guaranteed to be 42. Prior to Java-5, compiler was free to re-order the writes to x and v, so you could see x at zero after you've seen v set to true. This was confusing, and lead to subtle errors. Java-5 memory model addressed this issue by making volatile writes almost equivalent to synchronization.
volatileactually does on real hardware. We just imagine that there's all kinds of things an implementation might do and thatvolatileguarantees that optimizations don't produce particular behaviors that we need to prohibit in particular cases.