This post is the solution of Series About Java Concurrency – Pt. 3, so be sure to read my last post before this one.

So, what does the code from Series About Java Concurrency – Pt. 3 do? As it turns out, there isn’t a single answer: If you are using a recent Oracle VM the behavior of the program seems to depend on whether your VM runs in server or client mode. In client mode the program will most likely stop after roughly 2.5s as one would naively expect. In server mode however, the program just loops forever. The update to stop in line 24 never gets visible to the main thread. This isn’t a bug, but perfectly legal behavior according to the Java Memory Model, which allows optimizing

while(!stop)

into

while(true)

Synchronization is not just about avoiding data races; it is also needed to avoid reading stale data. This may sound weired, but allows the VM as well as the CPU to apply powerful optimizations (for example Out-of-order execution) that would otherwise be impossible or very hard to implement.

One way to fix our shiny little program is by using the synchronized keyword as demonstrated below:

package com.wordpress.mlangc.concurrent; public class PleaseWait { private static final long MILLIS_TO_WAIT = 2500; private static boolean stop = false; private static synchronized boolean isStop() { return stop; } private static synchronized void setStop(boolean stop) { PleaseWait.stop = stop; } public static void main(String[] args) { Thread timer = new Thread(new Runnable() { public void run() { try { Thread.sleep(MILLIS_TO_WAIT); } catch(InterruptedException e) { // We are already exiting the thread. } finally { setStop(true); System.out.println("Stop requested."); } } }); timer.start(); long start = System.currentTimeMillis(); while(!isStop()) ; // <-- Do nothing. long stoppedAfter = System.currentTimeMillis() - start; System.out.printf("Stopped after %dms.

", stoppedAfter); } }

It is important to note that both the setter and the getter are synchronized using the same lock. Synchronizing only the setter method is not enough!

While the code above works reasonably well, we can still do better because we don’t need mutual exclusion, but just want to ensure that main thread sees what the timer thread does. This can be accomplished quite easily by declaring stop to be volatile. The volatile keyword makes sure that the main thread always sees to most recent value of stop without any additional uses of synchronized. Following this advice, we end up with something like this:

package com.wordpress.mlangc.concurrent; public class PleaseWait { private static final long MILLIS_TO_WAIT = 2500; private static volatile boolean stop = false; public static void main(String[] args) { Thread timer = new Thread(new Runnable() { public void run() { try { Thread.sleep(MILLIS_TO_WAIT); } catch(InterruptedException e) { // We are already exiting the thread. } finally { stop = true; System.out.println("Stop requested."); } } }); timer.start(); long start = System.currentTimeMillis(); while(!stop) ; // <-- Do nothing. long stoppedAfter = System.currentTimeMillis() - start; System.out.printf("Stopped after %dms.

", stoppedAfter); } }

The only difference to the broken version from Series About Java Concurrency – Pt. 3 is the volatile keyword in line 6.

Last but not least I want to state clearly that this article is not about the proper way to implement task cancellation, which is a nontrivial topic of it’s own. If parts of this post are new to you, I strongly suggest that you grab yourself a copy of the excellent book Java Concurrency in Practice and read at least the first chapter called Fundamentals thoroughly. By doing so you are almost certainly saving yourself from nasty surprises or frustrating debugging session in the future.