Java Reference
In-Depth Information
In the case of fetching an item from the buffer, the condition that allows the operation to
proceed is that the
buffer is not empty
. If the condition in question is true, the operation
may proceed; if it's false, the thread must
wait
until it becomes true. When a thread is
waiting on a condition, it's removed from contention for the processor and placed into the
waiting
state and the lock it holds is released.
Methods
wait
,
notify
and
notifyAll
Object
methods
wait
,
notify
and
notifyAll
can be used with conditions to make threads
wait
when they cannot perform their tasks. If a thread obtains the
monitor lock
on an object,
then determines that it cannot continue with its task on that object until some condition is
satisfied, the thread can call
Object
method
wait
on the
synchronized
object; this
releases
the monitor lock
on the object, and the thread waits in the
waiting
state while the other
threads try to enter the object's
synchronized
statement(s) or method(s). When a thread
executing a
synchronized
statement (or method) completes or satisfies the condition on
which another thread may be waiting, it can call
Object
method
notify
on the
synchro-
nized
object to allow a waiting thread to transition to the
runnable
state again. At this
point, the thread that was transitioned from the
waiting
state to the
runnable
state can at-
tempt to
reacquire the monitor lock
on the object. Even if the thread is able to reacquire the
monitor lock, it still might not be able to perform its task at this time—in which case the
thread will reenter the
waiting
state and implicitly
release the monitor lock
. If a thread calls
notifyAll
on the
synchronized
object, then
all
the threads waiting for the monitor lock
become eligible to
reacquire the lock
(that is, they all transition to the
runnable
state).
Remember that only
one
thread at a time can obtain the monitor lock on the object—
other threads that attempt to acquire the same monitor lock will be
blocked
until the mon-
itor lock becomes available again (i.e., until no other thread is executing in a
synchronized
statement on that object).
Common Programming Error 23.1
It's an error if a thread issues a
wait
, a
notify
or a
notifyAll
on an object without hav-
ing acquired a lock for it. This causes an
IllegalMonitorStateException
.
Error-Prevention Tip 23.2
It's a good practice to use
notifyAll
to notify
waiting
threads to become
runnable
. Doing
so avoids the possibility that your program would forget about waiting threads, which
would otherwise starve.
Figures 23.16 and 23.17 demonstrate a
Producer
and a
Consumer
accessing a shared
buffer with synchronization. In this case, the
Producer
always produces a value
first
, the
Consumer
correctly consumes only
after
the
Producer
produces a value and the
Producer
correctly produces the next value only after the
Consumer
consumes the previous (or first)
value. We reuse interface
Buffer
and classes
Producer
and
Consumer
from the example in
Section 23.5, except that line 28 is removed from class
Producer
and class
Consumer
.
Class
SynchronizedBuffer
The synchronization is handled in class
SynchronizedBuffer
's
blockingPut
and
blocking-
Get
methods (Fig. 23.16), which implements interface
Buffer
(line 4). Thus, the
Producer
's
and
Consumer
's
run
methods simply call the shared object's
synchronized
blockingPut
and