Java Reference
In-Depth Information
Consumer reads 6 Buffer cells occupied: 0
Producer writes 7 Buffer cells occupied: 1
Consumer reads 7 Buffer cells occupied: 0
Producer writes 8 Buffer cells occupied: 1
Consumer reads 8 Buffer cells occupied: 0
Producer writes 9 Buffer cells occupied: 1
Consumer reads 9 Buffer cells occupied: 0
Producer writes 10 Buffer cells occupied: 1
Producer done producing
Terminating Producer
Consumer reads 10 Buffer cells occupied: 0
Consumer read values totaling 55
Terminating Consumer
Fig. 23.15 | Two threads manipulating a blocking buffer that properly implements the
producer/consumer relationship. (Part 2 of 2.)
While methods put and take of ArrayBlockingQueue are properly synchronized,
BlockingBuffer methods blockingPut and blockingGet (Fig. 23.14) are not declared to
be synchronized. Thus, the statements performed in method blockingPut —the put oper-
ation (line 17) and the output (lines 18-19)—are not atomic ; nor are the statements in
method blockingGet —the take operation (line 25) and the output (lines 26-27). So
there's no guarantee that each output will occur immediately after the corresponding put
or take operation, and the outputs may appear out of order. Even if they do, the Array-
BlockingQueue object is properly synchronizing access to the data, as evidenced by the fact
that the sum of values read by the consumer is always correct.
23.7 (Advanced) Producer/Consumer Relationship with
synchronized , wait , notify and notifyAll
[ Note: This section is intended for advanced programmers who want to control synchro-
nization. 2 ] The previous example showed how multiple threads can share a single-element
buffer in a thread-safe manner by using the ArrayBlockingQueue class that encapsulates
the synchronization necessary to protect the shared mutable data. For educational purpos-
es, we now explain how you can implement a shared buffer yourself using the synchro-
nized keyword and methods of class Object . Using an ArrayBlockingQueue generally
results in more-maintainable, better-performing code.
After identifying the shared mutable data and the synchronization policy (i.e., associ-
ating the data with a lock that guards it), the next step in synchronizing access to the buffer
is to implement methods blockingGet and blockingPut as synchronized methods. This
requires that a thread obtain the monitor lock on the Buffer object before attempting to
access the buffer data, but it does not automatically ensure that threads proceed with an
operation only if the buffer is in the proper state. We need a way to allow our threads to
wait , depending on whether certain conditions are true. In the case of placing a new item
in the buffer, the condition that allows the operation to proceed is that the buffer is not full .
2.
For detailed information on wait , notify and notifyAll , see Chapter 14 of Java Concurrency in
Practice by Brian Goetz, et al., Addison-Wesley Professional, 2006.
 
Search WWH ::




Custom Search