ReentrantLock 配合 Condition 是实现生产者消费者模式的推荐方式,支持多等待队列、可中断和超时等待;需用 while 循环判断条件、finally 中解锁、合理使用 signal/signalAll。

ReentrantLock 配合 Condition 是实现生产者消费者模式的推荐方式,比 synchronized + wait/notify 更灵活、更安全,尤其支持多个等待队列、可中断等待、超时等待等特性。
核心思路:一个锁 + 两个 Condition
用 ReentrantLock 保证线程安全,用两个 Condition 分别管理“空”和“满”两种等待状态:
- notFull:当队列满时,生产者在此 await;有消费者取走元素后,signal 生产者继续生产
- notEmpty:当队列空时,消费者在此 await;有生产者放入元素后,signal 消费者继续消费
典型实现(基于阻塞队列逻辑)
以下是一个简化但完整的示例(使用 ArrayDeque 模拟有限容量队列):
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
public class ProducerConsumerDemo {
private final ReentrantLock lock = new ReentrantLock();
private final Condition notFull = lock.newCondition();
private final Condition notEmpty = lock.newCondition();
private final Deque<String> queue = new ArrayDeque<>();
private final int capacity = 5;
public void produce(String item) throws InterruptedException {
lock.lock();
try {
while (queue.size() == capacity) {
notFull.await(); // 队列满,生产者等待
}
queue.offer(item);
System.out.println("生产: " + item + ", 当前数量=" + queue.size());
notEmpty.signal(); // 唤醒一个等待消费的线程
} finally {
lock.unlock();
}
}
public String consume() throws InterruptedException {
lock.lock();
try {
while (queue.isEmpty()) {
notEmpty.await(); // 队列空,消费者等待
}
String item = queue.poll();
System.out.println("消费: " + item + ", 当前数量=" + queue.size());
notFull.signal(); // 唤醒一个等待生产的线程
return item;
} finally {
lock.unlock();
}
}
}
关键细节和注意事项
- 必须用 while 循环判断条件,不能用 if:防止虚假唤醒(spurious wakeup)或被错误 signal 后条件已不满足
- await() 会自动释放锁,唤醒后重新竞争并获取锁:这是 Condition 的核心机制,无需手动 unlock/lock
- signal() vs signalAll():单个生产者/消费者场景用 signal 即可;存在多个同类线程且需全部响应变化时(如清空队列),考虑 signalAll
- 务必在 finally 块中 unlock:避免因异常导致锁永久持有
扩展建议:支持中断和超时
Condition 提供了更健壮的等待能力:
立即学习“Java免费学习笔记(深入)”;
-
awaitNanos(long nanosTimeout)或await(long time, TimeUnit unit):让等待可超时,避免无限阻塞 -
awaitInterruptibly():支持响应中断,调用线程被 interrupt 时抛出 InterruptedException 并退出等待 - 配合 Thread.interrupted() 可做优雅关闭(例如设置标志位 + 中断所有等待线程)

















