Java Reference
In-Depth Information
needs to be able to repair the damage. Consider an unbounded blocking stack in which the
pop operation blocks if the stack is empty but the push operation can always proceed. This
meets the requirements for single notification. If this class uses single notification and a sub-
class adds a blocking “pop two consecutive elements” method, there are now two classes of
waiters: those waiting to pop one element and those waiting to pop two. But if the base class
exposes the condition queue and documents its protocols for using it, the subclass can over-
ride the push method to perform a notifyAll , restoring safety.
14.2.7. Encapsulating Condition Queues
It is generally best to encapsulate the condition queue so that it is not accessible outside the
class hierarchy in which it is used. Otherwise, callers might be tempted to think they under-
stand your protocols for waiting and notification and use them in a manner inconsistent with
your design. (It is impossible to enforce the uniform waiters requirement for single notifica-
tion unless the condition queue object is inaccessible to code you do not control; if alien code
mistakenly waits on your condition queue, this could subvert your notification protocol and
cause a hijacked signal.)
Unfortunately, this advice—to encapsulate objects used as condition queues—is not consist-
ent with the most common design pattern for thread-safe classes, in which an object's intrins-
ic lock is used to guard its state. BoundedBuffer illustrates this common idiom, where
the buffer object itself is the lock and condition queue. However, BoundedBuffer could
be easily restructured to use a private lock object and condition queue; the only difference
would be that it would no longer support any form of client-side locking.
14.2.8. Entry and Exit Protocols
Wellings ( Wellings, 2004 ) characterizes the proper use of wait and notify in terms of
entry and exitprotocols . For each state-dependent operation and for each operation that mod-
ifies state on which another operation has a state dependency, you should define and docu-
ment an entry and exit protocol. The entry protocol is the operation's condition predicate; the
exit protocol involves examining any state variables that have been changed by the operation
to see if they might have caused some other condition predicate to become true, and if so,
notifying on the associated condition queue.
AbstractQueuedSynchronizer , upon which most of the state-dependent classes in
java.util.concurrent are built (see Section 14.4 ), exploits the concept of exit pro-
tocol. Rather than letting synchronizer classes perform their own notification, it instead re-
quires synchronizer methods to return a value indicating whether its action might have un-
Search WWH ::




Custom Search