You need to enable JavaScript to run this app. 为何双线程get/put同步的Java代码会抛出IllegalMonitorStateException?
优惠活动
大模型
产品
解决方案
定价
更多

为何双线程get/put同步的Java代码会抛出IllegalMonitorStateException?

IllegalMonitorStateException 根本触发原因

根据Java并发规范,调用任意对象的wait()/notify()/notifyAll()监视器方法时,当前线程必须持有该方法所属对象的监视器锁,无锁调用会立刻抛出IllegalMonitorStateException。

开发者经常存在规则误解:认为只要进入任意同步块,就可以自由调用wait/notify,但实际匹配逻辑是严格一一对应的——在持有X对象锁的同步块内,仅能合法调用X对象的监视器方法,调用其他对象的对应方法依然会触发异常。同时,无对象前缀的wait()/notify(),默认等价于调用当前类实例this的对应方法。

当前代码的具体错配点

  • 最直接的异常触发逻辑在put()方法中:
    方法全程只在synchronized (TransferObject.class)同步块内操作,线程持有的只有TransferObject.class类对象的锁,从未尝试获取当前TransferObject实例(this)的对象锁,却在块内直接调用了无对象前缀的wait()——等价于执行this.wait()。此时线程未持有this的监视器锁,完全满足异常触发条件。
  • 全局锁逻辑的错位:
    get()方法同时持有两层锁:先通过方法上的synchronized拿到this实例锁,再进入内部块拿到类对象锁。块内的notify()虽然因为持有this锁不会触发异常,但两个方法使用的锁对象完全不统一:Producer线程仅持有类锁,却操作this的等待队列;Consumer线程同时持有两层锁,同样操作this的等待队列。这种错位会导致就算异常被修复,线程间的等待、唤醒逻辑也完全失效,根本无法实现“put完成后get才能读取”的生产消费同步需求。
  • 设计层面的逻辑缺失:
    代码中定义的isValuePresent状态标记完全没有参与流程判断,当前流程就算不抛异常,也会出现“Producer写入值后立刻进入等待、Consumer无值时空转读取”的逻辑错误,无法保证读写时序的正确性。

快速修复异常的最小调整方式

所有和锁对象绑定的监视器调用,必须和当前持有的锁完全匹配。如果选择以TransferObject.class作为全局公共锁:

  • 去掉get()方法上多余的this实例锁,所有同步逻辑统一收敛到类对象锁的块内
  • 把隐式调用的this.wait()/this.notify()全部替换为显式的TransferObject.class.wait()/TransferObject.class.notify(),让所有监视器操作都对应线程已经持有的类对象锁

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.05 16:24:05