Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs

Programming Java threads in the real world, Part 2

The perils of race conditions, deadlock, and other threading problems

  • Print
  • Feedback

Page 4 of 7

Fix the problem by replacing the if statement with a while loop (called a spin lock). Now the threads that don't get the object will go back to waiting:

    public Object synchronized dequeue( )
    {
        try
        {   while( head == tail )  // used to be an if
                this.wait();
        }
        catch( InterruptedException e )
        {   return null;
        }
        return queue[++tail %= queue_size ]; 
    }


That while loop also solves another, less obvious problem. What if we leave the notify() statement in place, and don't put in a notifyAll()? Since notify() releases only one waiting thread, won't that solve the problem? It turns out that the answer is no. Here's what can happen:

  1. notify() is called by the enqueueing thread, releasing the condition variable.

  2. The dequeueing thread is then preempted, after being released from the wait on the condition variable, but before it tries to reacquire the monitor's lock.

  3. A second thread calls dequeue() at exactly this point, and successfully enters the monitor because no other threads are officially waiting. This second thread successfully dequeues the object; wait() is never called since the queue isn't empty.

  4. The original thread is now allowed to run, it acquires the monitor, doesn't test for empty a second time, and then dequeues garbage.


This second scenario is easily fixed the same way as the first: replace the if statement with a while loop.

Note that the Java specification does not require that wait() be implemented as an atomic operation (that is, one that can't be preempted while moving from the condition variable to the monitor's lock). This means that using an if statement instead of a while loop might work in some Java implementations, but the behavior is really undefined. Using a spin lock instead of a simple if statement is cheap insurance against implementations that don't treat wait() as atomic.

Threads are not objects

Now let's move on to harder-to-find problems. The first difficulty is the commonplace confusion of threads and objects: Methods run on threads, objects do not. Put another way, the only way to get a method to run on a given thread is to call it (either directly or indirectly) from that thread's run() method. Simply putting it into the Thread derivative is not enough. For example, look at the following simple thread (which just prints its fields every so often):

class My_thread extends Thread
{
    private int field_1 = 0;
    private int field_2 = 0;
    public void run()
    {   
        setDaemon(true);  // this thread will not keep the app alive
        while( true )
        {
            System.out.println( " field_1=" + field_1
                                    " field_2=" + field_2 );
            sleep(100);
        }
    }
    synchronized public void modify( int new_value )
    {   field_1 = new_value;
            field_2 = new_value;
    }
}


You could start up the thread and send it a message like this:

My_thread test = new My_thread;
test.start();
//...
test.modify(1);


The only functions that run on the new thread are run() itself and println() (which run() calls). The modify() method never runs on the same thread as the println call; rather, it runs on whatever thread was running when the call was made. (In this case, it runs on whatever thread main() is running on.) Depending on timing, the earlier fragment could print:

  • Print
  • Feedback

Resources
  • Sun's Technical Articles page has several articles on multithreading http://developer.javasoft.com/developer/technicalArticles/#thread
  • Prashant Jain and Douglas C. Schmidt have a good article contrasting C++ to Java that discusses many of the thread-related problems inherent in the language. The article can be found at http://www.cs.wustl.edu/%7Eschmidt/C++2java.html
  • Doug Lea has a bunch of Mutex and Condition-variable classes in his util.concurrent package. See http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html
  • Doug Schmidt's Ace Framework is a good, though complex, attempt at a truly platform-independent threading system http://www.cs.wustl.edu/~schmidt/
  • There are several good books that discuss the Java threading issues mentioned in the first article in this series. For convenience, I've listed them again here:
  • For a great in-depth look at multithreading in general and the implementation of multithreading both in and with Java in particular, this is a must. It's required reading if you're using threads heavilyDoug Lea, Concurrent Programming in JavaDesign Principles and Patterns (ReadingAddison Wesley, 1997) http://java.sun.com/docs/books/cp/
  • For a book on Java threading that is less technical but more readable than Lea's, seeScott Oaks and Henry Wong, Java Threads (Sebastopol, Calif.O'Reilly, 1997) http://www.oreilly.com/catalog/jthreads/
  • This book is good for the general subject of multithreading but doesn't have a Java slantBill Lewis and Daniel J. Berg, Threads PrimerA Guide to Multithreaded Programming (Englewood CliffsPrentice Hall/SunSoft Press, ISBN 0-13-443698-9) http://www.sun.com/books/books/Lewis/Lewis.html