Java Reference
In-Depth Information
The
Producer
thread remains in the
waiting
state until another thread
notifies
the
Producer
that it may proceed—at which point the
Producer
returns to the
runnable
state
and attempts to implicitly reacquire the lock on the
SynchronizedBuffer
object. If the
lock is available, the
Producer
thread reacquires it, and method
blockingPut
continues
executing with the next statement after the
wait
call. Because
wait
is called in a loop, the
loop-continuation condition is tested again to determine whether the thread can proceed.
If not, then
wait
is invoked again—otherwise, method
blockingPut
continues with the
next statement after the loop.
Line 22 in method
blockingPut
assigns the
value
to the
buffer
. Line 26 sets
occu-
pied
to
true
to indicate that the
buffer
now contains a value (i.e., a consumer can read
the value, but a
Producer
cannot yet put another value there). Line 28 invokes method
displayState
to output a message indicating that the
Producer
is writing a new value into
the
buffer
. Line 30 invokes method
notifyAll
(inherited from
Object
). If any threads
are
waiting
on the
SynchronizedBuffer
object's monitor lock, those threads enter the
runnable
state and can now attempt to
reacquire the lock
. Method
notifyAll
returns
immediately, and method
blockingPut
then returns to the caller (i.e., the
Producer
's
run
method). When method
blockingPut
returns, it
implicitly releases the monitor lock
on the
SynchronizedBuffer
object.
Method
blockingGet
and the
Consumer
Thread
Methods
blockingGet
and
blockingPut
are implemented similarly. When the
Consumer
thread's
run
method invokes
synchronized
method
blockingGet
, the thread attempts to
acquire the monitor lock
on the
SynchronizedBuffer
object. If the lock is available, the
Consumer
thread acquires it. Then the
while
loop at lines 37-43 determines whether
oc-
cupied
is
false
. If so, the buffer is empty, so line 40 outputs a message indicating that the
Consumer
thread is trying to read a value, and line 41 invokes method
displayState
to
output a message indicating that the buffer is
empty
and that the
Consumer
thread is
wait-
ing
. Line 42 invokes method
wait
to place the thread that called method
blockingGet
(i.e., the
Consumer
) in the
waiting
state for the
SynchronizedBuffer
object. Again, the call
to
wait
causes the calling thread to
implicitly release the lock
on the
SynchronizedBuffer
object, so another thread can attempt to acquire the
SynchronizedBuffer
object's lock
and invoke the object's
blockingPut
or
blockingGet
method. If the lock on the
Synchro-
nizedBuffer
is not available (e.g., if the
Producer
has not yet returned from method
blockingPut
), the
Consumer
is
blocked
until the lock becomes available.
The
Consumer
thread remains in the
waiting
state until it's
notified
by another thread
that it may proceed—at which point the
Consumer
thread returns to the
runnable
state and
attempts to
implicitly reacquire the lock
on the
SynchronizedBuffer
object. If the lock is
available, the
Consumer
reacquires it, and method
blockingGet
continues executing with
the next statement after
wait
. Because
wait
is called in a loop, the loop-continuation con-
dition is tested again to determine whether the thread can proceed with its execution. If
not,
wait
is invoked again—otherwise, method
blockingGet
continues with the next
statement after the loop. Line 47 sets
occupied
to
false
to indicate that
buffer
is now
empty (i.e., a
Consumer
cannot read the value, but a
Producer
can place another value in
buffer
), line 49 calls method
displayState
to indicate that the consumer is reading and
line 51 invokes method
notifyAll
. If any threads are in the
waiting
state for the lock on
this
SynchronizedBuffer
object, they enter the
runnable
state and can now attempt to