I\'m trying to illustrate the use and importance of volatile with an example that would really not give a good result if volatile was omitted.
It was always hard to me to illustrate concurrency problems in a convincing way: well, fine, it's all nice about happens-before and stuff, but why should one care? Is there a real problem? There are lots and lots of poorly written, poorly synchronized programs—and they still work most of the time.
I used to find a resort in a "works most of the time VS works" rhetoric—but, frankly, it's a weak approach. So what I needed is an example which would make difference obvious—and, preferably, painful.
So here is a version which actually does show the difference:
public class VolatileExample implements Runnable {
public static boolean flag = true; // do not try this at home
public void run() {
long i = 0;
while (flag) {
if (i++ % 10000000000L == 0)
System.out.println("Waiting " + System.currentTimeMillis());
}
}
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new VolatileExample());
thread.start();
Thread.sleep(10000L);
flag = false;
long start = System.currentTimeMillis();
System.out.println("stopping " + start);
thread.join();
long end = System.currentTimeMillis();
System.out.println("stopped " + end);
System.out.println("Delay: " + ((end - start) / 1000L));
}
}
A simple run shows:
Waiting 1319229217263
stopping 1319229227263
Waiting 1319229242728
stopped 1319229242728
Delay: 15
That is, it takes more than ten seconds (15 here) for a running thread to notice there was any change.
With volatile, you have:
Waiting 1319229288280
stopping 1319229298281
stopped 1319229298281
Delay: 0
that is, exiting (almost) immediately. The resolution of currentTimeMillis is around 10ms, so the difference is more that 1000 times.
Note it was Apple's version of (ex-)Sun JDK, with -server option. The 10-second wait was added in order to let JIT compiler find out that the loop is hot enough, and optimize it.
Hope that helps.