Java Reference
In-Depth Information
48
49
displayState(
"Consumer reads "
+ buffer);
// for demo only
50
51
notifyAll();
// tell waiting thread(s) to enter runnable state
52
53
return
buffer;
54
}
// end method blockingGet; releases lock on SynchronizedBuffer
55
56
// display current operation and buffer state; for demo only
57
private
synchronized
void
displayState(String operation)
58
{
59
System.out.printf(
"%-40s%d\t\t%b%n%n"
, operation, buffer,
60
occupied);
61
}
62
}
// end class SynchronizedBuffer
Fig. 23.16
|
Synchronizing access to shared mutable data using
Object
methods
wait
and
notifyAll
. (Part 2 of 2.)
Fields and Methods of Class
SynchronizedBuffer
Class
SynchronizedBuffer
contains fields
buffer
(line 6) and
occupied
(line 7)—you
must synchronize access to
both
fields to ensure that class
SynchronizedBuffer
is thread
safe. Methods
blockingPut
(lines 10-31) and
blockingGet
(lines 34-54) are declared as
synchronized
—only
one
thread can call either of these methods at a time on a particular
SynchronizedBuffer
object. Field
occupied
is used to determine whether it's the
Produc-
er
's or the
Consumer
's turn to perform a task. This field is used in conditional expressions
in both the
blockingPut
and
blockingGet
methods. If
occupied
is
false
, then
buffer
is
empty, so the
Consumer
cannot read the value of
buffer
, but the
Producer
can place a val-
ue into
buffer
. If
occupied
is
true
, the
Consumer
can read a value from
buffer
, but the
Producer
cannot place a value into
buffer
.
Method
blockingPut
and the
Producer
Thread
When the
Producer
thread's
run
method invokes
synchronized
method
blockingPut
,
the thread implicitly attempts to acquire the
SynchronizedBuffer
object's monitor lock.
If the monitor lock is available, the
Producer
thread
implicitly
acquires the lock. Then the
loop at lines 14-20 first determines whether
occupied
is
true
. If so,
buffer
is
full
and we
want to wait until the buffer is empty, so line 17 outputs a message indicating that the
Producer
thread is trying to write a value, and line 18 invokes method
displayState
(lines 57-61) to output another message indicating that
buffer
is
full
and that the
Pro-
ducer
thread is
waiting
until there's space. Line 19 invokes method
wait
(inherited from
Object
by
SynchronizedBuffer
) to place the thread that called method
blockingPut
(i.e.,
the
Producer
thread) in the
waiting
state for the
SynchronizedBuffer
object. The call to
wait
causes the calling thread to
implicitly
release the lock on the
SynchronizedBuffer
ob-
ject. This is important because the thread cannot currently perform its task and because
other threads (in this case, the
Consumer
) should be allowed to access the object to allow
the condition (
occupied
) to change. Now another thread can attempt to acquire the
Syn-
chronizedBuffer
object's lock and invoke the object's
blockingPut
or
blockingGet
method.