/** * Implements a bounded buffer. * @author Mathias Ricken */ public class BoundedBuffer implements IBoundedBuffer { /** * Buffer with data. */ private T _buffer[]; /** * The index for the next read. */ private int _readIndex; /** * The index for the next write. */ private int _writeIndex; /** * True if the last access was a write. * If both the read and write indices are equal and _lastWrite is true, then the buffer is full. * If both the read and write indices are equal and _lastWrite is false, then the buffer is empty. */ private boolean _lastWrite; /** * Create a new bounded buffer that can contain size items. * @param size number of items the buffer can contain */ @SuppressWarnings("unchecked") public BoundedBuffer(int size) { _buffer = (T[])new Object[size]; _readIndex = 0; _writeIndex = 0; _lastWrite = false; } /** * Write an item into the bounded buffer. Waits until an entry is available. * @param item item to write * @throws InterruptedException */ public synchronized void write(T item) throws InterruptedException { while(isFull()) { wait(); } _buffer[_writeIndex] = item; _writeIndex = getNextIndex(_writeIndex); _lastWrite = true; notify(); } /** * Read an item from the bounded buffer. Waits until an entry is available. * @return item read * @throws InterruptedException */ public synchronized T read() throws InterruptedException { while(isEmpty()) { wait(); } T item = _buffer[_readIndex]; _readIndex = getNextIndex(_readIndex); _lastWrite = false; notify(); return item; } /** * Given an index, returns the next index, performing wrapping. * @param index index * @return next index */ private int getNextIndex(int index) { return (index+1) % _buffer.length; } /** * Returns true if the buffer is full. * A buffer is full if the two indices are the same and the last access was a write. * @return true if the buffer is full. */ private boolean isFull() { return (_writeIndex == _readIndex) && (_lastWrite); } /** * Returns true if the buffer is empty. * A buffer is full if the two indices are the same and the last access was a read. * @return true if the buffer is full. */ private boolean isEmpty() { return (_readIndex == _writeIndex) && (!_lastWrite); } }