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 6 of 7

As I mentioned above, Wilma and Betty are a contrived example, but the multiple-lock situation comes up frequently. I'll give a more detailed example next month.

Get out the magnifying glass

If all deadlock scenarios were as easy to recognize as Wilma and Betty, deadlock wouldn't be a problem. Consider the following code, though:

class Boss
{
    private Side_kick robin;
    public synchronized void set_side_kick( Side_kick kid_in_tights )
    {   robin = kid_in_tights;
    };
    public synchronized void to_the_bat_cave()
    {   robin.get_in_the_car(); 
    }
    public synchronized void okay()     // sent to us by robin
    {   //...
    }
    public synchronized void hold_on()  // sent to us by robin
    {   //...
    }
}
//-------------------------------------------------------
class Side_kick
{
    private Boss batman;
    public synchronized void set_boss( Boss guy_in_cape )
    {   batman = guy_in_cape;
    }
    public synchronized void get_in_the_car()   // sent by batman
    {   batman.okay();
    }
    public synchronized void sock_bam_pow()     // sent from outside
    {   batman.hold_on();
    }
}
//-------------------------------------------------------
class Gotham_city
{   static Boss      batman = new Boss();
    static Side_kick robin  = new Side_kick();
    public static void main( String[] args )
    {
        batman.set_side_kick( robin );
        robin.set_boss( batman );
        // spawn off a bunch of threads that use batman and robin.
    }
}


Now imagine the following:

  1. One thread (call it Alfred) issues a to_the_bat_cave() request to the batman object passed to it from main().

  2. The batman object starts to process the method, but is preempted just before it calls robin.get_in_the_car(). At this juncture, Alfred has acquired the lock for the batman object.

  3. Now along comes a second thread (call it Joker), which issues a sock_bam_pow() message to the robin object that it got from main().

  4. The robin object (whose sock_bam_pow() method is running on the Joker thread) tries to send a hold_on() message to batman, but can't because Alfred owns the lock on batman. So the Joker thread is now blocked, waiting for Alfred to release the lock on batman.

  5. Now Alfred gets a chance to run, and it tries to send a get_in_the_car() message to the robin object, but it can't because the Joker thread owns the lock on robin. Both threads are now deadlocked (sound familiar?)


Remember: threads own the locks and methods execute on threads, not objects.

This situation is, of course, much harder to see than the Wilma-and-Betty problem because the locks in the batman-robin example are the natural locks associated with individual objects. There are no standalone synchronized statements in the batman-robin code, and the locks are associated with two completely distinct objects.

Multithreaded programmers tear their hair out looking for the causes of these sorts of problems, and there are only two solutions. The first is to thoroughly design the code before implementing it, and then to really study both the design and the implementation before you even think about running it the first time. When I do multithreaded programs, I spend much more time on code and design reviews than I spend on coding.

  • 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