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

使用wait/notify同步共享EntityManager触发IllegalMonitorStateException问题排查

EntityManager调用notify()抛出IllegalMonitorStateException的原因及修复

问题场景

我需要检查当前事务是否未处于活跃状态,以执行新事务,因此对共享的EntityManager采用wait()和notify()实现同步,代码如下:

public static void getTransaction() throws Throwable {
    EntityManager em = getEntityManager();
    synchronized (em) {
        if (em.getTransaction().isActive()) {
            em.wait();
        }
    }
    return executeTransaction();
}

public static void executeTransaction(){
    EntityManager em = getEntityManager();
    synchronized (em) {
        EntityTransaction tx = em.getTransaction();
        tx.begin;
        //execute persist operations
        tx.commit();
        em.notify();
    }
}

运行时调用em.notify()抛出如下错误:

Caused by: java.lang.IllegalMonitorStateException: null
at java.lang.Object.notify(Native Method)

问题原因

1. 同步对象不一致(核心原因)

IllegalMonitorStateException触发的条件是调用notify()/wait()的线程没有持有该对象的监视器锁。这里最可能的情况是getEntityManager()每次返回的不是同一个EntityManager实例:

  • 在getTransaction()中获取的EntityManager实例,和executeTransaction()中获取的实例不是同一个对象
  • 两个方法分别对不同的对象加锁,此时executeTransaction()中调用notify()的对象,并不是之前getTransaction()中调用wait()的对象,线程虽然持有当前em的锁,但逻辑上完全不匹配,最终触发异常。

2. wait()判断逻辑存在虚假唤醒风险

即使getEntityManager()返回单例,用if判断事务状态也不安全——Java的wait()可能被虚假唤醒(无通知情况下恢复执行),这会导致事务仍活跃时就进入新事务,引发并发问题。

3. 语法错误

代码中tx.begin缺少括号,正确写法是tx.begin();,这会导致编译失败。

修复方案

  • 保证同步对象一致:确保getEntityManager()返回同一个EntityManager单例实例,让wait()和notify()操作的是同一个对象的监视器锁。
  • 修正wait()判断逻辑:用while循环替代if,持续检查事务状态,避免虚假唤醒:
    synchronized (em) {
        while (em.getTransaction().isActive()) {
            em.wait();
        }
    }
    
  • 修复语法错误:将tx.begin改为tx.begin();。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 09:01:12