Java Reference
In-Depth Information
Chapter 14. Building Custom Synchronizers
The class libraries include a number of state-dependent classes—those having operations with
state-based preconditions —such as FutureTask , Semaphore , and BlockingQueue .
For example, you cannot remove an item from an empty queue or retrieve the result of a task
that has not yet finished; before these operations can proceed, you must wait until the queue
enters the “nonempty” state or the task enters the “completed” state.
The easiest way to construct a state-dependent class is usually to build on top of an existing
state-dependent library class; we did this in ValueLatch on page 187 , using a Coun-
tDownLatch to provide the required blocking behavior. But if the library classes do not
provide the functionality you need, you can also build your own synchronizers using the
low-level mechanisms provided by the language and libraries, including intrinsic condition
queues , explicit Condition objects, and the AbstractQueuedSynchronizer frame-
work. This chapter explores the various options for implementing state dependence and the
rules for using the state dependence mechanisms provided by the platform.
14.1. Managing State Dependence
In a single-threaded program, if a state-based precondition (like “the connection pool is
nonempty”) does not hold when a method is called, it will never become true. Therefore,
classes in sequential programs can be coded to fail when their preconditions do not hold. But in
a concurrent program, state-based conditions can change through the actions of other threads:
a pool that was empty a few instructions ago can become nonempty because another thread
returned an element. State-dependent methods on concurrent objects can sometimes get away
with failing when their preconditions are not met, but there is often a better alternative: wait
for the precondition to become true.
State-dependent operations that block until the operation can proceed are more convenient and
less error-prone than those that simply fail. The built-in condition queue mechanism enables
threads to block until an object has entered a state that allows progress and to wake blocked
threads when they may be able to make further progress. We cover the details of condition
queues in Section 14.2 , but to motivate the value of an efficient condition wait mechanism, we
first show how state dependence might be (painfully) tackled using polling and sleeping.
A blocking state-dependent action takes the form shown in Listing 14.1 . The pattern of locking
is somewhat unusual in that the lock is released and reacquired in the middle of the opera-
tion. The state variables that make up the precondition must be guarded by the object's lock,
Search WWH ::




Custom Search