Java Reference
In-Depth Information
Because multiple threads could be waiting on the same condition queue for different condi-
tion predicates, using
notify
instead of
notifyAll
can be dangerous, primarily because
single notification is prone to a problem akin to missed signals.
BoundedBuffer
provides a good illustration of why
notifyAll
should be preferred to
single
notify
in most cases. The condition queue is used for two different condition predic-
ates: “not full” and “not empty”. Suppose thread
A
waits on a condition queue for predicate
PA
, while thread
B
waits on the same condition queue for predicate
PB
. Now, suppose
PB
becomes true and thread
C
performs a single
notify
: the JVM will wake up one thread of
its own choosing. If
A
is chosen, it will wake up, see that
PA
is not yet true, and go back to
waiting. Meanwhile,
B
, which could now make progress, does not wake up. This is not ex-
actly a missed signal—it's more of a “hijacked signal”—but the problem is the same: a thread
is waiting for a signal that has (or should have) already occurred.
Single
notify
can be used instead of
notifyAll
only when both of the following condi-
tions hold:
Uniform waiters.
Only one condition predicate is associated with the condition queue,
and each thread executes the same logic upon returning from
wait
; and
One-in, one-out.
A notification on the condition variable enables at most one thread to
proceed.
BoundedBuffer
meets the one-in, one-out requirement, but does not meet the uniform
waiters requirement because waiting threads might be waiting for either the “not full” and
in which a single event releases a set of threads, does not meet the one-in, one-out require-
ment because opening the starting gate lets multiple threads proceed.
Most classes don't meet these requirements, so the prevailing wisdom is to use
notifyAll
in preference to single
notify
. While this may be inefficient, it is much easier to ensure
that your classes behave correctly when using
notifyAll
instead of
notify
.
This “prevailing wisdom” makes some people uncomfortable, and for good reason. Using
notifyAll
when only one thread can make progress is inefficient—sometimes a little,
sometimes grossly so. If ten threads are waiting on a condition queue, calling
notifyAll
causes each of them to wake up and contend for the lock; then most or all of them will go
right back to sleep. This means a lot of context switches and a lot of contended lock acquis-