The java.util.concurrent tools

Developers who've been using Doug Lea's concurrency tools know what a boon they are for building multithreaded apps in Java. Soon all Java developers will benefit from his work--read how this library is going to simplify your multithreaded development.

Java is a language built with threading in mind. The java.lang.Thread class has been around since release 1.0, synchronized is one of the built-in keywords, and java.lang.Object has had wait, notify, and notifyAll methods throughout. These basic tools allow for rudimentary thread control. However, during the design and development of software, situations arise where the correct multithreaded behavior is difficult to achieve using basic wait, notify, and synchronized.

Avoiding the race condition
Faced with exacting threading requirements, developers had one of two options. They could carefully use the tools Java provides to achieve the required semantics or, with substantially reduced effort, they could get their threading ninety percent correct and hope to win the race condition lottery. Many developers, sometimes unknowingly, took the second option.

Six years ago Doug Lea started writing high quality, efficient, semantically correct thread control constructs built atop the basic Java synchronization tools. This collection, called util.concurrent, can help developers who previously may have taken the easy, approximate course to achieve strictly correct threading behavior without an increase in effort.

The util.concurrent classes offer specialty implementations of a handful of basic interfaces. The Sync interface and its implementors provide tools for locking. Locks are often used to restrict access to resources. The Barrier family of classes helps out when multiple threads need to join to perform tasks in a coordinated fashion. Barriers are particularly useful when more than one independent task must finish before another task can begin.

The Sync interface
Objects implementing the Sync interface offer, at least, the acquire() and release() methods. Threads wishing to take possession of the Sync call the acquire() method and then wait until it is their turn to gain ownership of the Sync. Once done with a Sync, the possessing thread is then responsible for calling release on the sync. The behavior of a Sync is very similar to that of an Object's monitor. However, whereas synchronized methods and blocks are lexically scoped, the acquisition and release of a Sync can be done anywhere.

When multiple threads are waiting to acquire a Sync, the eventual order in which ownership is offered to them depends on which specific Sync implementation is selected. Options for Sync scheduling include first come first served and thread priority based, among others. Also available on all Sync implementations is the attempt method, which allows for the providing of a maximum duration for which a Sync should be waited.

Bringing threads back together with the Barrier interface
When multiple threads are each performing their assigned tasks, there come times when they need to get back together to exchange data or combine their results. The Barrier interface provides mechanisms for allowing separate threads to join at a single point in time.

The two provided implementations of the Barrier interface allow for slightly different behavior when all the expected threads arrive. The CyclicBarrier waits until the specified number of threads have called the barrier method and then a single thread, the last of them, calls the specified Runnable. In contrast, the Rendezvous Barrier invokes a specified method on the value provided by each joining thread. The default action function for the Rendezvous hands off each thread's parameter to the rendezvous method to the next thread in line.

At first it may be difficult to imagine situations where Barriers might be a helpful construct. However, when one keeps them in mind during development, it turns out that all manner of situations can be simplified through their use. Computational tasks that can be segmented for processing but need their results recombined for reporting are a natural. Other uses include blocking close() calls until separate reading and writing tasks on a socket are complete or more generally separately verifying preconditions before taking any action.

Coming soon to standard Java
Developers have been using Doug Lea's concurrency tools for years, but soon a great many more will learn about them. A modified version will be made available in a future JDK update. Java Specification Request 166, as found on Sun's Java Community Process pages, details the portions to be included and the related changes that will take place in existing packages in the core classes. Having these powerful tools automatically available to all Java developers should result in reduced race conditions and deadlocked threads.

Editor's Picks