reentrantlock的condition唤醒失效主因有三:一是condition必须与创建它的锁绑定,跨锁调用signal/await静默失效;二是await必须用while循环检查条件且妥善处理interruptedexception;三是signal需在锁内调用并紧邻unlock,避免耗时操作阻塞唤醒线程。

ReentrantLock.newCondition() 唤醒失效?先确认是否在同把锁上操作
用 newCondition() 创建的 Condition 对象,必须和调用它的 ReentrantLock 实例绑定使用。唤醒失败最常见的原因是:线程 A 在 lock1 上调用 condition.await(),线程 B 却在 lock2 上调用 condition.signal() —— 这根本不会触发唤醒,也不会报错,只是静默失效。
- 每个
Condition只属于创建它的那一个ReentrantLock实例,不能跨锁复用 - 检查
await()和signal()是否包裹在同一个lock.lock()/lock.unlock()临界区内 - 若需多条件协同,应为同一把锁创建多个
Condition(如notEmpty、notFull),而非混用不同锁的 condition
await() 被中断后没重试?必须手动处理 InterruptedException
await() 是可中断的阻塞方法,一旦被中断会抛出 InterruptedException 并自动释放锁。但很多人忽略这点,直接吞掉异常或不重入等待逻辑,导致线程“假唤醒”后跳过条件检查就继续执行,引发数据不一致。
- 永远不要在
catch (InterruptedException e)里只写e.printStackTrace()或空 catch - 标准做法是恢复中断状态(
Thread.currentThread().interrupt()),并根据业务决定是否重试await() - 典型模式:
while (!conditionMet()) { condition.await(); }—— 条件检查必须用 while,不能用 if
signal() 唤醒后立即 unlock()?别让唤醒线程卡在锁竞争上
signal() 只是把等待线程从条件队列移到同步队列,并不释放锁。如果唤醒后立刻 unlock(),被唤醒线程仍需竞争锁;但如果 signal 后还持有锁太久,又会拖慢响应。关键在于唤醒时机和锁粒度的平衡。
-
signal()必须在持有锁时调用,但尽量靠近unlock()前执行,减少被唤醒线程的等待时间 - 避免在
signal()后再做耗时操作(如 IO、复杂计算),否则等于人为加长锁持有时间 - 如果唤醒后要立即修改共享状态,确保这些修改也在同一把锁保护下,否则可能被其他线程插队破坏条件
Condition 不支持超时 await 的精确唤醒?得靠 awaitNanos() 配合状态轮询
await(long time, TimeUnit unit) 看似支持超时,但它在超时后返回时,**不保证条件已满足**,也不保证未被中断 —— 它只是“等够了时间就回来”,此时你仍要手动检查条件、处理中断、决定是否继续等。真要精准控制,得用 awaitNanos() + 自旋计时。
立即学习“Java免费学习笔记(深入)”;
-
awaitNanos()返回剩余纳秒数,负值表示已超时;正值可传给下一次调用,实现精确总等待时长 - 超时后必须检查共享变量状态,不能假设“时间到了就一定可以干活”
- 注意 JVM 休眠精度(尤其 Windows 下可能几十毫秒偏差),对微秒级唤醒要求高的场景,
Condition本身不是最佳选择










