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):
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
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;
}
}</t></t>
注意:notifyAll() 比 notify() 更安全——避免唤醒错误类型的线程(比如只唤醒另一个生产者,而消费者仍在挂起)。
线程安全与边界细节
这个实现是线程安全的,但有几个实用细节要注意:
- 构造时指定容量,不可变;运行中不修改
capacity - 使用
ArrayList时,remove(0)是 O(n),如需高性能可用ArrayDeque或循环数组 - 如果要求公平性(先到先服务),
notifyAll()仍不能保证,JVM 不保证唤醒顺序;真要强公平需用ReentrantLock+Condition - 实际项目中优先用
java.util.concurrent.ArrayBlockingQueue,它正是基于类似逻辑封装的成熟实现
不复杂但容易忽略:锁、循环等待、唤醒时机,这三者缺一不可。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










