condition.await()不唤醒的主因是未在reentrantlock保护下调用或signal()先于await()执行;必须用同一condition实例、while循环检查条件;signal()用于互斥条件,signalall()用于影响多个等待者;lock+condition与synchronized+wait/notify不可混用;await()响应中断需恢复中断状态。

Condition.await() 为什么线程不唤醒?
最常见的情况是:await() 调用前没在 ReentrantLock 的保护下获取锁,或者 signal() 发生在 await() 之前(即“信号丢失”)。Condition 不像 Object.wait()/notify() 那样自带锁语义,它完全依赖外部 Lock 的状态。
实操要点:
-
await()必须在lock.lock()之后、lock.unlock()之前调用,否则抛IllegalMonitorStateException - 唤醒逻辑必须和等待逻辑使用同一个
Condition实例(不能 new 多个) - 典型写法是 while 循环检查条件,而非 if —— 因为
await()可能被虚假唤醒或信号被抢走
lock.lock();
try {
while (!ready) {
condition.await(); // ✅ 正确:在 lock 保护内
}
// do work...
} finally {
lock.unlock();
}
signal() 和 signalAll() 到底选哪个?
signal() 唤醒一个等待线程(具体哪个由 JVM 决定),signalAll() 唤醒所有。选错会导致死锁或资源浪费。
判断依据:
- 如果等待条件是“互斥”的(比如只有一个缓冲区槽位空闲),用
signal()更高效 - 如果条件变化会影响多个等待者(比如“所有消费者都该重试读取”或“全局状态变更”),必须用
signalAll() - 不确定时优先用
signalAll()—— 安全但有性能开销;确认无竞争再优化为signal()
注意:signal() 不保证唤醒“最先等待”的线程,也不保证唤醒后立即执行 —— 它只是把线程从等待队列移到同步队列,仍需重新竞争锁。
Condition 和 Object.wait() 混用会怎样?
完全不能混用。它们底层机制不同:Object.wait() 绑定对象监视器,Condition 绑定 AbstractQueuedSynchronizer 的等待队列。混用会导致线程永远挂起,且无任何异常提示。
典型错误:
- 在
synchronized块里调用condition.await()→ 抛IllegalMonitorStateException - 用
ReentrantLock加锁后,却对某个对象调用obj.wait()→ 线程阻塞,但没人能notify()它(因为没人在该对象上synchronized) - 一个线程用
Condition.await(),另一个用obj.notify()→ 信号彻底丢失
记住:Lock + Condition 是一套,synchronized + wait/notify 是另一套,不要跨套通信。
await() 被中断时怎么处理?
await() 是响应中断的,一旦线程被 interrupt(),会抛出 InterruptedException 并自动释放关联的锁。这是它比 Object.wait() 更可控的地方。
正确做法:
- 捕获
InterruptedException后,通常应恢复中断状态:Thread.currentThread().interrupt() - 不要“吞掉”中断 —— 否则上层调用者无法感知取消意图
- 若在循环中 await,中断后一般应退出循环或清理资源
try {
condition.await();
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // ✅ 保留中断标记
return; // 或 throw new RuntimeException(e);
}
真正容易被忽略的是:awaitNanos()、awaitUntil() 这类带超时的方法,在超时返回后不会抛异常,但线程中断状态可能已被清除 —— 调用前最好先检查 Thread.interrupted()。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










