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

为何Java的ReentrantLock要求调用Condition方法前必须持有锁?

Java中ReentrantLock的Condition为何要求调用信号/等待方法前持有锁?
  • 保证条件检查与状态操作的原子性
    Condition是配合锁实现「等待-通知」模式的工具,正常使用的范式是先加锁,再检查条件,不满足就等待,满足后执行操作再通知其他线程。如果不强制持有锁,线程在检查条件和调用await/signal的间隙,可能被其他线程修改条件状态,比如线程A刚判断条件不满足,还没调用await,线程B就修改了条件并发出通知,这时候A再await就会错过通知,陷入永久等待,直接破坏业务逻辑的正确性。

  • 对齐Java内置监视器的语义习惯
    Java里用synchronized配合wait()/notify()时,同样要求调用线程持有对象锁。ReentrantLock作为显式锁,Condition的设计延续了这一规则,让开发者不用切换思维模式,降低学习成本和误用概率。

  • 避免Condition等待队列的并发混乱
    Condition内部维护着等待线程的队列,如果允许无锁调用signal/await,多个线程同时操作这个队列会引发竞态条件——比如节点的添加、移除操作可能出现不一致,导致线程管理混乱,甚至触发死锁。持有锁能保证对Condition队列的操作是串行化的,从机制上避免这类问题。

对比C++的std::condition_variable,它确实允许无锁调用通知方法,但这要求开发者手动用锁保护条件状态的检查和修改,本质是把锁的持有要求从API层面转移到了编码规范上。Java选择在API层面强制锁持有,是为了避免开发者因疏忽遗漏锁的使用,从根源上减少并发bug。

实际测试中,未持有锁调用Condition方法会抛出明确异常:

java.lang.IllegalMonitorStateException
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.signalAll(AbstractQueuedSynchronizer.java:1954)
    at PingPongPrinter_.printPing(PingPong2.java:35)
    at WorkerPing.run(PingPong2.java:53)
    at java.lang.Thread.run(Thread.java:748)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 06:00:47