SpringBoot内嵌Tomcat写数据抛IllegalMonitorStateException原因
异常触发原因
IllegalMonitorStateException是JDK原生抛出的运行时异常,触发前提是:调用Object.wait()系列方法的线程,并未持有被调用wait方法对象的监视器锁(即没有在包裹该对象的synchronized同步块中执行wait逻辑)。
结合你使用的tomcat-embed-core:9.0.31版本和异常堆栈,这是Tomcat NIO连接器的已知并发回归Bug,具体逻辑如下:
- 9.0.31版本修改NioSocketWrapper的写逻辑时,引入了锁时序漏洞:当HTTP响应写回过程中遇到NIO发送缓冲区已满的情况,代码逻辑会调用
wait()等待通道可写事件,但高并发场景下存在概率出现线程未成功持有NioSocketWrapper实例的监视器锁,就直接进入wait调用分支,直接抛出该异常。 - 高负载场景下触发频率升高的原因是:并发量越高,同一连接的写操作排队、NIO发送缓冲区被打满的概率越高,多线程争抢SocketWrapper锁的时序冲突概率也随之上升,和你观察到的故障特征完全匹配。
- 该Bug是9.0.31版本专属的回归问题,不涉及业务代码逻辑错误。
修复方案
- 永久修复:升级Tomcat依赖版本到修复该Bug的稳定版本
- 若使用SpringBoot管理依赖,将SpringBoot版本升级到2.2.6及以上的2.2.x稳定版,其内置的Tomcat版本为9.0.35+,已经合入该锁问题的修复补丁
- 若单独指定Tomcat依赖版本,直接将
tomcat-embed-core等Tomcat相关组件的版本升级到9.0.35及以上的9.0.x稳定版本即可,不建议跨大版本升级避免引入兼容性问题
- 临时规避方案(无法立即升级版本时使用)
- 将Tomcat的连接器IO模型从默认的NIO切换为NIO2或APR,绕过NIO模型下存在Bug的写等待逻辑
- 适当调大Tomcat连接器的写缓冲区配置,降低高负载下发送缓冲区打满触发wait等待的概率,注意该方案只能降低异常触发频率,无法彻底解决问题
内容的提问来源于stack exchange,提问作者yangchenwen
相关产品推荐
相关产品推荐

