java中用condition的await()和signal()实现多条件精确唤醒,核心是每个条件绑定独立condition实例并共用reentrantlock;await()需在lock保护下用while循环检查条件,signal()只唤醒对应condition的等待线程。

Java 中用 Condition 的 await() 和 signal() 实现多条件线程精确唤醒,核心在于:每个条件对应一个独立的 Condition 实例,配合同一个 ReentrantLock 使用,避免无差别唤醒(如 notifyAll())带来的性能浪费和逻辑混乱。
Condition 必须绑定到 ReentrantLock 上
Condition 不是独立存在的,它必须由 ReentrantLock.newCondition() 创建。一个锁可以创建多个 Condition,每个代表一类等待条件。
错误写法:
❌ 不要使用 Object.wait()/notify() 混搭 Condition;
❌ 不要跨锁复用同一个 Condition;
❌ 不要在 synchronized 块里调用 Condition 方法(会抛 IllegalMonitorStateException)。
正确结构示例:
private final ReentrantLock lock = new ReentrantLock(); private final Condition notFull = lock.newCondition(); // 缓冲区未满 private final Condition notEmpty = lock.newCondition(); // 缓冲区非空
await() 必须在 lock 保护下调用,且需配合 while 循环检查条件
await() 会释放当前锁并挂起线程,但被唤醒后**不自动重新获取锁**,而是进入锁竞争队列;唤醒后必须重新检查条件是否真正满足(防止虚假唤醒或条件已变)。
- 调用前必须已持有锁(否则抛
IllegalMonitorStateException) - 务必用
while (conditionNotMet) await();,而非if - 唤醒后再次加锁成功,才继续执行后续逻辑
例如生产者等待“未满”:
lock.lock();
try {
while (queue.size() == capacity) {
notFull.await(); // 释放锁,挂起
}
queue.offer(item);
notEmpty.signal(); // 唤醒一个消费者
} finally {
lock.unlock();
}
signal() / signalAll() 只唤醒对应条件的等待线程
signal() 从该 Condition 的等待队列中选一个线程唤醒;signalAll() 唤醒全部。关键点:
- 只影响调用
await()在这个Condition上的线程 - 不会唤醒在其他
Condition上等待的线程(实现精确控制) - 唤醒不立即执行,只是让线程重新竞争锁;获得锁后仍需检查条件
典型场景:生产者/消费者模型中,生产者 put 后只 signal() 消费者等待的 notEmpty,不影响其他条件。
注意中断与超时的正确处理
await() 支持响应中断和设置超时,但需显式处理异常:
-
awaitNanos(long)、awaitUntil(Date)返回剩余纳秒数或 false,用于判断是否超时 -
await()被中断时抛InterruptedException,应捕获并恢复中断状态(Thread.currentThread().interrupt()) - 不要忽略中断,否则可能破坏上层调度逻辑
示例(带中断支持):
try {
while (!ready) {
notReady.await();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 恢复中断标志
throw new RuntimeException("Wait interrupted", e);
}Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











