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.