Java Reference
In-Depth Information
like LinkedBlockingQueue , CountDown-Latch , Semaphore , and FutureTask
when you can; if you can get away with it, it is a lot easier.)
14.2.1. The Condition Predicate
The key to using condition queues correctly is identifying the condition predicates that the
object may wait for. It is the condition predicate that causes much of the confusion surround-
ing wait and notify , because it has no instantiation in the API and nothing in either the
language specification or the JVM implementation ensures its correct use. In fact, it is not
mentioned directly at all in the language specification or the Javadoc. But without it, condi-
tion waits would not work.
The condition predicate is the precondition that makes an operation state-dependent in the
first place. In a bounded buffer, take can proceed only if the buffer is not empty; otherwise
it must wait. For take , the condition predicate is “the buffer is not empty”, which take
must test for before proceeding. Similarly, the condition predicate for put is “the buffer is
not full”. Condition predicates are expressions constructed from the state variables of the
class; BaseBoundedBuffer tests for “buffer not empty” by comparing count to zero,
and tests for “buffer not full” by comparing count to the buffer size.
Document the condition predicate(s) associated with a condition queue and the operations
that wait on them.
There is an important three-way relationship in a condition wait involving locking, the wait
method, and a condition predicate. The condition predicate involves state variables, and the
state variables are guarded by a lock, so before testing the condition predicate, we must hold
that lock. The lock object and the condition queue object (the object on which wait and no-
tify are invoked) must also be the same object.
In BoundedBuffer , the buffer state is guarded by the buffer lock and the buffer object is
used as the condition queue. The take method acquires the buffer lock and then tests the
condition predicate (that the buffer is nonempty). If the buffer is indeed nonempty, it removes
the first element, which it can do because it still holds the lock guarding the buffer state.
If the condition predicate is not true (the buffer is empty), take must wait until another
thread puts an object in the buffer. It does this by calling wait on the buffer's intrinsic condi-
tion queue, which requires holding the lock on the condition queue object. As careful design
Search WWH ::




Custom Search