Condition 实现精准唤醒的核心是每个语义条件绑定独立 Condition 对象,如 notEmpty 和 notFull 隔离唤醒;需用 while 循环校验条件、正确配对 lock/unlock,并确保 await/signal 在同一锁下执行。

Java 中的 Condition 实现精准唤醒,核心在于:每个 Condition 实例绑定到一个 ReentrantLock 上,不同业务逻辑使用**独立的 Condition 对象**,配合 signal() 或 signalAll(),只唤醒等待在该条件上的线程。
一、为什么 Condition 能比 wait/notify 更精准?
wait()/notify() 依赖对象监视器(monitor),所有线程共用同一等待队列,notify() 无法指定唤醒哪个逻辑分支的线程,容易发生“虚假唤醒”或唤醒错人。
而 Condition 是由 Lock 创建的,一个锁可创建多个互不干扰的条件队列。比如:
-
notEmpty:用于“非空”条件,唤醒等待取数据的消费者 -
notFull:用于“非满”条件,唤醒等待存数据的生产者
两者完全隔离 —— notEmpty.signal() 只唤醒调用了 notEmpty.await() 的线程,不会影响 notFull.await() 的线程。
二、关键操作步骤(以阻塞队列为例)
以下是一个简化但完整的生产者-消费者场景片段:
private final ReentrantLock lock = new ReentrantLock();
private final Condition notEmpty = lock.newCondition(); // 消费者等待
private final Condition notFull = lock.newCondition(); // 生产者等待
private final List<Integer> buffer = new ArrayList<>();
private final int capacity = 10;
// 生产者
public void put(int item) throws InterruptedException {
lock.lock();
try {
while (buffer.size() == capacity) {
notFull.await(); // 等待「非满」条件
}
buffer.add(item);
notEmpty.signal(); // 有数据了,通知一个消费者
} finally {
lock.unlock();
}
}
// 消费者
public int take() throws InterruptedException {
lock.lock();
try {
while (buffer.isEmpty()) {
notEmpty.await(); // 等待「非空」条件
}
int item = buffer.remove(0);
notFull.signal(); // 空出位置,通知一个生产者
return item;
} finally {
lock.unlock();
}
}
三、精准唤醒的三个要点
-
每个语义条件配一个 Condition:不要多个业务共用同一个
Condition,否则 signal 就失去“精准”意义 - 用 while 而非 if 检查条件:防止虚假唤醒或被错误 signal 后条件仍不满足,必须循环校验
-
signal() vs signalAll():
signal()唤醒一个等待线程(更高效,推荐);signalAll()唤醒全部,适合条件变化后多个线程都可能满足的情况(如所有等待线程都在等“资源重置”)
四、常见误区提醒
⚠️ 注意:Condition 必须与它所属的 Lock 配合使用,且 await() 和 signal() 必须在持有同一把锁的前提下调用,否则抛 IllegalMonitorStateException。
另外,await() 会自动释放锁,并在被唤醒重新获取锁后才返回 —— 这个过程是原子的,无需手动 unlock/lock。


















