Lock + two conditions
Time O(1) per operation Space O(capacity)enqueue: while full, notFull.await(); add; notEmpty.signal(). dequeue: while empty, notEmpty.await(); remove; notFull.signal().
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
class BoundedBlockingQueue {
private final Deque<Integer> items = new ArrayDeque<>();
private final int capacity;
private final ReentrantLock lock = new ReentrantLock();
private final Condition notFull = lock.newCondition(), notEmpty = lock.newCondition();
public BoundedBlockingQueue(int capacity) { this.capacity = capacity; }
public void enqueue(int element) throws InterruptedException {
lock.lock();
try {
while (items.size() == capacity) notFull.await();
items.addLast(element);
notEmpty.signal();
} finally {
lock.unlock();
}
}
public int dequeue() throws InterruptedException {
lock.lock();
try {
while (items.isEmpty()) notEmpty.await();
int x = items.removeFirst();
notFull.signal();
return x;
} finally {
lock.unlock();
}
}
public int size() {
lock.lock();
try { return items.size(); } finally { lock.unlock(); }
}
}Verdict: Separate conditions wake only the right kind of waiter.