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
In his recent " Design for thread safety" article (part of the Design Techniques column), Bill Venners introduced the notion of a race condition, a situation whereby two threads simultaneously contend for the same object and, as a consequence, leave the object in an undefined state. Bill pointed out that Java's synchronized keyword is in the language to help avoid these problems, and he provided a straightforward example of its use. Last month's article was the first in a series on threads. The present article continues that series, covering race conditions in depth. It also discusses various deadlock scenarios, which are related to race conditions but are much harder to find and debug. This month, we'll focus primarily on the problems encountered when programming Java threads. Subsequent Java Toolbox columns will focus entirely on solutions.

Monitors, mutexes, and bathrooms

Just to make sure we're all starting from the same place, a little review of terms is in order. The central concept for synchronization in the Java model is the monitor, developed some 20 years ago by C. A. R. Hoare. A monitor is a body of code guarded by a mutual-exclusion semaphore (or, to use a term coined at Digital Equipment Corp., a mutex). The central notion of a mutex concerns ownership. Only one thread can own the mutex at a time. If a second thread tries to "acquire" ownership, it will block (be suspended) until the owning thread "releases" the mutex. If several threads are all waiting to acquire the same mutex, they will all be released simultaneously when the owning thread releases the mutex. The released threads will then have to sort out amongst themselves who gains ownership. (Typically, priority order, FIFO order, or some combination thereof is used to determine which thread gains control.) You guard a block of code by acquiring a mutex at the top of the block and releasing it at the bottom. The code comprising the monitor does not have to be contiguous: several discontiguous code blocks can all acquire and release the same mutex, in which case all of this code is considered to be in the same monitor because it uses a common mutex.

The best analogy I've heard for a monitor is an airplane bathroom. Only one person can be in the bathroom at a time (we hope). Everybody else is queued up in a rather narrow aisle waiting to use it. As long as the door is locked, the bathroom is unaccessible. Given these terms, in our analogy the object is the airplane, the bathroom is the monitor (assuming there's only one bathroom), and the lock on the door is the mutex.

In Java, every object has one and only one monitor and mutex associated with it. The single monitor has several doors into it, however, each indicated by the synchronized keyword. When a thread passes over the synchronized keyword, it effectively locks all the doors. Of course, if a thread doesn't pass across the synchronized keyword, it hasn't locked the door, and some other thread is free barge in at any time.

Bear in mind that the monitor is associated with the object, not the class. Several threads can all be executing the same method in parallel, but the receiving objects (as identified by the this references) have to be different. For example, several instances of a thread-safe queue could be in use by several threads. These threads could simultaneously enqueue objects to different queues, but they could not enqueue to the same queue at the same time. Only one thread at a time can be in the monitor for a given queue.

  • 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