You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java Condition.await()收到signal后需等unlock()才唤醒的原因

核心结论

你观察到的运行结果完全符合Java Condition的设计规范,和Javadoc描述没有冲突,问题出在你对await()返回条件的理解有遗漏。

关键逻辑说明

Javadoc只提到signal()是唤醒等待线程的触发条件之一,但没有明确说透await()方法返回的硬性前置要求:

被signal()唤醒的线程,必须重新获取到与当前Condition绑定的锁,才能真正从await()方法处返回,继续执行后续代码。

调用signal()本身不会释放锁,锁的持有权仍然保留在调用signal()的线程手中,直到该线程主动调用unlock()方法释放锁。

对应代码的执行流程拆解
  • 线程1首先拿到rLock,休眠1s后进入while循环调用cond.await():这一步确实原子性释放了锁,线程1进入Condition的专属等待队列休眠,不再参与锁调度。
  • 之前因为抢不到锁阻塞的线程2此时成功获取锁,执行到cond.signal():这一步的作用仅仅是把线程1从Condition等待队列移动到rLock的锁竞争队列,标记线程1具备后续抢锁的资格,但此时锁仍然被线程2持有,线程1根本没有机会拿到锁,自然无法从await()返回打印Step5。
  • 线程2继续执行后续逻辑:休眠3s、修改aBool的值,直到进入finally块调用rLock.unlock()释放锁,此时锁变为可用状态,在锁竞争队列等待的线程1才能拿到锁,从await()方法返回,执行Step5的打印逻辑。

你实际运行得到的输出完全符合上述执行逻辑:

(Step 1) Thread 1 locks and sleeps 1s
(Step 2) Thread 2 also requires lock, blocked
(Step 3) Thread 1 enters while loop
(Step 4) Thread 2 gets lock after thread 1 cond wait, sends signal
(Step 6) Thread 2 sleeps 3s and set aBool
(Step 7) unlock
(Step 5) Thread 1 got signal
常见认知误区

很多人会混淆「线程被标记为唤醒」和「线程立刻获得执行权」两个概念,实际上Condition的signal()/await()机制和内置锁的Object.notify()/wait()机制逻辑完全一致:调用notify()后,被唤醒的线程同样需要等持有synchronized锁的线程释放锁、自己重新拿到锁之后,才能从wait()方法返回,不存在调用唤醒方法后被唤醒线程立刻插队执行的情况。

如果要实现你预期的Step5在Step6前执行的效果,只需要在cond.signal()调用后立刻释放锁,等线程1执行完对应逻辑后,线程2再重新抢锁执行后续操作即可,但这种写法需要严格控制锁的持有粒度,避免出现逻辑错误。

内容的提问来源于stack exchange,提问作者gongliming7

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 14:51:22