Java中用wait()和notify()实现有界阻塞队列的核心是:用synchronized保护共享状态,入队/出队前用while循环检查条件(避免虚假唤醒),成功操作后调用notifyAll()唤醒等待方。

Java 中用 wait() 和 notify() 实现有界阻塞队列,核心在于用对象监视器(monitor)配合条件判断,让生产者在队列满时等待、消费者在队列空时等待,并在状态变化后及时唤醒对方。
用 synchronized 保护共享状态
所有对队列操作(入队、出队)和条件检查(是否满、是否空)都必须在同一个锁下进行,通常选择队列自身(this)或一个专用锁对象。否则会出现竞态条件或 IllegalMonitorStateException。
- 入队前检查容量:若
size == capacity,调用wait()暂停线程 - 出队前检查元素:若
size == 0,同样wait() - 每次成功入队/出队后,必须调用
notifyAll()(推荐)或notify()唤醒等待方
正确使用 wait() 的经典范式
wait() 必须放在 while 循环中,不能用 if。因为线程可能被虚假唤醒(spurious wakeup),或多个线程竞争时条件已再次不满足。
- 错误写法:
if (queue.size() == capacity) wait(); - 正确写法:
while (queue.size() == capacity) wait(); - 同理,出队时用
while (queue.isEmpty()) wait();
实现关键方法:put 和 take
以下是一个简化但完整的实现片段(基于 ArrayList):
立即学习“Java免费学习笔记(深入)”;
public class BoundedQueue<T> {
private final List<T> queue = new ArrayList<>();
private final int capacity;
public BoundedQueue(int capacity) {
this.capacity = capacity;
}
public synchronized void put(T item) throws InterruptedException {
while (queue.size() == capacity) {
wait(); // 队列满,生产者等待
}
queue.add(item);
notifyAll(); // 唤醒可能等待的消费者
}
public synchronized T take() throws InterruptedException {
while (queue.isEmpty()) {
wait(); // 队列空,消费者等待
}
T item = queue.remove(0);
notifyAll(); // 唤醒可能等待的生产者
return item;
}
}
注意:notifyAll() 比 notify() 更安全——避免唤醒错误类型的线程(比如只唤醒另一个生产者,而消费者仍在挂起)。
线程安全与边界细节
这个实现是线程安全的,但有几个实用细节要注意:
- 构造时指定容量,不可变;运行中不修改
capacity - 使用
ArrayList时,remove(0)是 O(n),如需高性能可用ArrayDeque或循环数组 - 如果要求公平性(先到先服务),
notifyAll()仍不能保证,JVM 不保证唤醒顺序;真要强公平需用ReentrantLock+Condition - 实际项目中优先用
java.util.concurrent.ArrayBlockingQueue,它正是基于类似逻辑封装的成熟实现
不复杂但容易忽略:锁、循环等待、唤醒时机,这三者缺一不可。


















