Condition支持多等待队列,使Lock能按业务条件精准唤醒线程;Object的wait/notify仅有一个全局队列,notify()随机唤醒、notifyAll()全唤醒,易导致无效竞争。

Java中用对象锁(synchronized)配合wait()/notify()只能实现粗粒度唤醒,而Lock + Condition组合才能做到按条件精准唤醒——比如只唤醒生产者、不惊动消费者,或只唤醒特定类型的等待线程。
为什么需要Condition而不是Object.wait/notify
Object的wait()和notify()绑定在单一对象监视器上,所有等待线程共用一个等待队列。调用notify()是随机唤醒一个,notifyAll()则全唤醒,容易引发“唤醒错人”或“无效竞争”。Condition把等待队列拆开管理,一个Lock可配多个Condition,每个代表一类业务条件。
- 生产者等待“队列未满”,挂入
notFull队列 - 消费者等待“队列非空”,挂入
notEmpty队列 -
notFull.signal()只唤醒生产者,notEmpty.signal()只唤醒消费者
基本使用四步法
Condition不能独立存在,必须依附于Lock,且所有操作需在加锁后进行:
- 创建
ReentrantLock实例,如Lock lock = new ReentrantLock(); - 调用
lock.newCondition()生成条件对象,如Condition notEmpty = lock.newCondition(); - 线程在临界区检查条件,不满足时调用
condition.await()——该操作自动释放锁并进入对应等待队列 - 另一线程变更共享状态后,调用
condition.signal()或signalAll()唤醒指定队列中的线程
关键细节与避坑点
Condition的正确性高度依赖编码规范:
立即学习“Java免费学习笔记(深入)”;
-
必须用while循环判断条件:防止伪唤醒(spurious wakeup),例如
while (queue.isEmpty()) notEmpty.await(); -
await()前必须已持有锁,否则抛
IllegalMonitorStateException -
signal()后不立即释放锁:被唤醒线程需重新竞争锁,获得锁后才从
await()返回 - 务必在finally块中unlock():避免死锁,这是显式锁区别于synchronized的核心约束
典型场景:双Condition协同(生产者-消费者)
以固定容量缓冲区为例,两个Condition分工明确:
- 生产者线程:获取锁 → 检查
buffer.size() == MAX_SIZE→ 是则notFull.await()→ 否则入队 → 调用notEmpty.signal() - 消费者线程:获取锁 → 检查
buffer.isEmpty()→ 是则notEmpty.await()→ 否则出队 → 调用notFull.signal() - 两者互不干扰,唤醒目标精确,无冗余调度开销


















