Java Reference
In-Depth Information
85
System.out.printf( "%n%n" );
86
}
87
} // end class CircularBuffer
Fig. 23.18 | Synchronizing access to a shared three-element bounded buffer. (Part 3 of 3.)
Line 5 initializes array buffer as a three-element int array that represents the circular
buffer. Variable occupiedCells (line 7) counts the number of elements in buffer that
contain data to be read. When occupiedBuffers is 0 , the circular buffer is empty and the
Consumer must wait —when occupiedCells is 3 (the size of the circular buffer), the cir-
cular buffer is full and the Producer must wait . Variable writeIndex (line 8) indicates the
next location in which a value can be placed by a Producer . Variable readIndex (line 9)
indicates the position from which the next value can be read by a Consumer . Circular-
Buffer 's instance variables are all part of the class's shared mutable data, thus access to all
of these variables must be synchronized to ensure that a CircularBuffer is thread safe.
CircularBuffer Method blockingPut
CircularBuffer method blockingPut (lines 12-31) performs the same tasks as in
Fig. 23.16, with a few modifications. The loop at lines 17-21 determines whether the
Producer must wait (i.e., all buffer cells are full ). If so, line 19 indicates that the Producer
is waiting to perform its task. Then line 20 invokes method wait , causing the Producer
thread to release the CircularBuffer 's lock and wait until there's space for a new value to
be written into the buffer. When execution continues at line 23 after the while loop, the
value written by the Producer is placed in the circular buffer at location writeIndex . Then
line 26 updates writeIndex for the next call to CircularBuffer method blockingPut .
This line is the key to the buffer's circularity . When writeIndex is incremented past the
end of the buffer , the line sets it to 0 . Line 28 increments occupiedCells , because there's
now one more value in the buffer that the Consumer can read. Next, line 29 invokes meth-
od displayState (lines 57-86) to update the output with the value produced, the number
of occupied buffer cells, the contents of the buffer cells and the current writeIndex and
readIndex . Line 30 invokes method notifyAll to transition waiting threads to the run-
nable state, so that a waiting Consumer thread (if there is one) can now try again to read a
value from the buffer.
CircularBuffer Method blockingGet
CircularBuffer method blockingGet (lines 34-54) also performs the same tasks as it did
in Fig. 23.16, with a few minor modifications. The loop at lines 38-42 (Fig. 23.18) de-
termines whether the Consumer must wait (i.e., all buffer cells are empty ). If the Consumer
must wait , line 40 updates the output to indicate that the Consumer is waiting to perform
its task. Then line 41 invokes method wait , causing the current thread to release the lock
on the CircularBuffer and wait until data is available to read. When execution eventually
continues at line 44 after a notifyAll call from the Producer , readValue is assigned the
value at location readIndex in the circular buffer. Then line 47 updates readIndex for the
next call to CircularBuffer method blockingGet . This line and line 26 implement the
circularity of the buffer. Line 49 decrements occupiedCells , because there's now one
more position in the buffer in which the Producer thread can place a value. Line 50 in-
vokes method displayState to update the output with the consumed value, the number
Search WWH ::




Custom Search