Java中wait()、notify()、notifyAll()为何需由持有监视器的线程调用?
为什么调用wait()/notify()/notifyAll()必须持有对象监视器所有权?
这背后本质是为了避免竞态条件、保证线程协作逻辑的正确性,具体可以拆解成这几个原因:
防止检查条件与等待操作的竞态
调用wait()的前提通常是先检查某个条件(比如队列是否为空),如果没有synchronized保护,线程A刚检查完条件为真,还没调用wait(),线程B就可能修改了条件并调用notify()。等A再调用wait()时,它已经错过了通知,会一直阻塞下去,这就导致了逻辑错误。synchronized能把「检查条件+调用wait()」变成原子操作,中间不会被其他线程打断。保证wait/notify的锁交互逻辑合法
wait()执行时会自动释放当前持有的监视器锁,让其他线程能获取锁并修改条件。但你不能释放一个不属于你的锁——这就像你没法把别人的门打开让别人进一样。同样,notify()/notifyAll()是用来唤醒等待该监视器锁的线程,如果你没持有这个锁,你根本没有权限操作这个锁对应的等待队列,强行调用只会打乱其他线程的协作逻辑。避免不可预测的线程混乱
Java通过抛出IllegalMonitorStateException来强制这个约束,本质是防止线程随意操作不属于自己的对象监视器。比如一个线程随便调用某个对象的notify(),可能会唤醒正在等待该对象的无关线程,导致这些线程错误地认为条件满足,进而执行错误的逻辑,让整个程序进入不可控状态。
举个生产者消费者模型的错误与正确对比:
// 错误写法:无synchronized,存在竞态风险且会抛异常 if (queue.isEmpty()) { queue.wait(); // 运行时直接抛IllegalMonitorStateException } // 正确写法:用synchronized保证原子性 synchronized(queue) { // 用while循环是为了被唤醒后再次检查条件(防止虚假唤醒) while (queue.isEmpty()) { queue.wait(); } Object item = queue.poll(); }
内容的提问来源于stack exchange,提问作者Hossam
相关产品推荐
相关产品推荐

