Home > Programming > Series About Java Concurrency – Pt. 4

Series About Java Concurrency – Pt. 4

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.\n", 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.\n", 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.

Advertisements
Categories: Programming Tags: , ,
  1. ZeissS
    May 20, 2011 at 19:21

    When I currently do sthg like that, instead of using my own ‘stop’ variable I use the interrupted()/interrupt() method’s of the Thread class.

    Any danger in doing so?

    • May 20, 2011 at 19:57

      As I wrote, task cancellation is a nontrivial topic of it’s own, but of course you are right: Thread.interrupt() and related APIs should be preferred for various reasons over hand crafted stop flags.

  2. willjcroz
    May 21, 2011 at 00:49

    Don’t use Thread.interrupt() for task cancellation if you have many short lived threads being cancelled and/or you need the thread to cancel quickly. There’s no guarantee on the JVM response time; the stack trace construction each time is expensive too.

    Also, Thread.interrupt() is really a polite request for a thread to stop if it ‘feels like it’. Be careful where your thread needing to be cancelled may be executing. e.g. it could be inside a blocking call inside third party code that silently ignores the interruption.

    http://stackoverflow.com/questions/1914898/java-long-running-task-thread-interrupt-vs-cancel-flag/1915026#1915026

    An interesting but related aside is never to rely on wait(long millis) as any source of reliable timing. Spurious wakeups are mentioned in Object.wait(long millis) javadoc and they happen surprisingly often, which caught me out in a big way!

  3. Amit
    May 29, 2011 at 14:09

    Thanks for a good tech read. So the rule for using volatile variables would be to use it when only one thread modifies the state and all others just read. Did I understood it correctly?

    • May 29, 2011 at 23:28

      If you are sure that there are no data races or for some reason don’t care about them (for example because you are using a volatile field to cache a value), you can use volatile fields even when multiple threads might modify them instead of explicit locking. Be careful however if mutable objects are involved (following a volatile reference to a mutable object might still result in stale reads regarding the objects state), or when a field participates in invariants with other state variables. If you are interested in lock-free thread-safe programming, also take a serious look at atomic variables.

  4. Anonymous
    August 25, 2011 at 03:09

    Volatile is less used word in java and with change in Java 5 memory model, now volatile keyword guarantees the changes made by one thread to be visible in another thread if you have mark the variable as volatile.

    source: volatile keyword example in java

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: