java - EJB 两个单例相互调用死锁

标签 java ejb deadlock apache-tomee

我有 2 个 EJB @Singleton 在 tomee 中运行

他们正在互相调用,并陷入僵局

@Startup
@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
public class DeadlockReproducer {
    private final Logger LOGGER = Logger.getInstance(LogCategory.OPENEJB_STARTUP_CONFIG, this.getClass());

    @EJB
    private DeadlockReproducerAid deadlockReproducerAid;

    @PostConstruct
    public  void reproduce(){
        LOGGER.info("reproduce");
        deadlockReproducerAid.lockMe();
    }

    public void youCantGetMe(){
        LOGGER.info("youCantGetMe");
    }
}


@Startup
@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
public class DeadlockReproducerAid {
    private final Logger LOGGER = Logger.getInstance(LogCategory.OPENEJB_STARTUP_CONFIG, this.getClass());

    @EJB
    DeadlockReproducer deadlockReproducer;

    public void lockMe(){
        LOGGER.info("lockMe");
        deadlockReproducer.youCantGetMe();
    }
}

当 youCantGetMe 等待重现返回时,我遇到了僵局。

这是堆栈跟踪:

"localhost-startStop-1" #68 daemon prio=5 os_prio=0 tid=0x0000000056d1f000 nid=0x14e0 waiting on condition [0x0000000058aab000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000000fc7a2cc8> (a java.util.concurrent.FutureTask)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
    at java.util.concurrent.FutureTask.awaitDone(FutureTask.java:429)
    at java.util.concurrent.FutureTask.get(FutureTask.java:191)
    at org.apache.openejb.core.singleton.SingletonInstanceManager.getInstance(SingletonInstanceManager.java:112)
    at org.apache.openejb.core.singleton.SingletonContainer.invoke(SingletonContainer.java:200)
    at org.apache.openejb.core.ivm.EjbObjectProxyHandler.synchronizedBusinessMethod(EjbObjectProxyHandler.java:308)
    at org.apache.openejb.core.ivm.EjbObjectProxyHandler.businessMethod(EjbObjectProxyHandler.java:303)
    at org.apache.openejb.core.ivm.EjbObjectProxyHandler._invoke(EjbObjectProxyHandler.java:92)
    at org.apache.openejb.core.ivm.BaseEjbProxyHandler.invoke(BaseEjbProxyHandler.java:308)
    at com.company.test.eu.logic.server.stateMachine.DeadlockReproducer$$LocalBeanProxy.youCantGetMe(com/company/test/eu/logic/server/stateMachine/DeadlockReproducer.java)
    at com.company.test.eu.logic.server.stateMachine.DeadlockReproducerAid.lockMe(DeadlockReproducerAid.java:31)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.apache.openejb.core.interceptor.ReflectionInvocationContext$Invocation.invoke(ReflectionInvocationContext.java:192)
    at org.apache.openejb.core.interceptor.ReflectionInvocationContext.proceed(ReflectionInvocationContext.java:173)
    at org.apache.openejb.monitoring.StatsInterceptor.record(StatsInterceptor.java:181)
    at org.apache.openejb.monitoring.StatsInterceptor.invoke(StatsInterceptor.java:100)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.apache.openejb.core.interceptor.ReflectionInvocationContext$Invocation.invoke(ReflectionInvocationContext.java:192)
    at org.apache.openejb.core.interceptor.ReflectionInvocationContext.proceed(ReflectionInvocationContext.java:173)
    at org.apache.openejb.core.interceptor.InterceptorStack.invoke(InterceptorStack.java:85)
    at org.apache.openejb.core.singleton.SingletonContainer._invoke(SingletonContainer.java:256)
    at org.apache.openejb.core.singleton.SingletonContainer.invoke(SingletonContainer.java:212)
    at org.apache.openejb.core.ivm.EjbObjectProxyHandler.synchronizedBusinessMethod(EjbObjectProxyHandler.java:308)
    at org.apache.openejb.core.ivm.EjbObjectProxyHandler.businessMethod(EjbObjectProxyHandler.java:303)
    at org.apache.openejb.core.ivm.EjbObjectProxyHandler._invoke(EjbObjectProxyHandler.java:92)
    at org.apache.openejb.core.ivm.BaseEjbProxyHandler.invoke(BaseEjbProxyHandler.java:308)
    at com.company.test.eu.logic.server.stateMachine.DeadlockReproducerAid$$LocalBeanProxy.lockMe(com/company/test/eu/logic/server/stateMachine/DeadlockReproducerAid.java)
    at com.company.test.eu.logic.server.stateMachine.DeadlockReproducer.reproduce(DeadlockReproducer.java:30)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.apache.openejb.core.interceptor.ReflectionInvocationContext$Invocation.invoke(ReflectionInvocationContext.java:192)
    at org.apache.openejb.core.interceptor.ReflectionInvocationContext$LifecycleInvocation.invoke(ReflectionInvocationContext.java:223)
    at org.apache.openejb.core.interceptor.ReflectionInvocationContext.proceed(ReflectionInvocationContext.java:173)
    at org.apache.openejb.monitoring.StatsInterceptor.record(StatsInterceptor.java:181)
    at org.apache.openejb.monitoring.StatsInterceptor.PostConstruct(StatsInterceptor.java:109)
    at sun.reflect.GeneratedMethodAccessor37.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.apache.openejb.core.interceptor.ReflectionInvocationContext$Invocation.invoke(ReflectionInvocationContext.java:192)
    at org.apache.openejb.core.interceptor.ReflectionInvocationContext.proceed(ReflectionInvocationContext.java:173)
    at org.apache.openejb.core.interceptor.InterceptorStack.invoke(InterceptorStack.java:85)
    at org.apache.openejb.BeanContext.newInstance(BeanContext.java:1590)
    at org.apache.openejb.core.singleton.SingletonInstanceManager.createInstance(SingletonInstanceManager.java:179)
    at org.apache.openejb.core.singleton.SingletonInstanceManager.access$100(SingletonInstanceManager.java:69)
    at org.apache.openejb.core.singleton.SingletonInstanceManager$1.call(SingletonInstanceManager.java:120)
    at org.apache.openejb.core.singleton.SingletonInstanceManager$1.call(SingletonInstanceManager.java:118)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at org.apache.openejb.core.singleton.SingletonInstanceManager.getInstance(SingletonInstanceManager.java:129)
    at org.apache.openejb.core.singleton.SingletonInstanceManager.initialize(SingletonInstanceManager.java:93)
    at org.apache.openejb.core.singleton.SingletonInstanceManager.start(SingletonInstanceManager.java:84)
    at org.apache.openejb.core.singleton.SingletonContainer.start(SingletonContainer.java:125)
    at org.apache.openejb.assembler.classic.Assembler.startEjbs(Assembler.java:1168)
    at org.apache.openejb.assembler.classic.Assembler.createApplication(Assembler.java:807)
    at org.apache.openejb.assembler.classic.Assembler.createApplication(Assembler.java:623)
    at org.apache.tomee.catalina.TomcatWebAppBuilder.startInternal(TomcatWebAppBuilder.java:1248)
    at org.apache.tomee.catalina.TomcatWebAppBuilder.configureStart(TomcatWebAppBuilder.java:1087)
    at org.apache.tomee.catalina.GlobalListenerSupport.lifecycleEvent(GlobalListenerSupport.java:130)
    at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:117)
    at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:90)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5378)
    - locked <0x00000000e1115938> (a org.apache.catalina.core.StandardContext)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    - locked <0x00000000e1115938> (a org.apache.catalina.core.StandardContext)
    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901)
    at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877)
    at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:649)
    at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:1083)
    at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1880)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

   Locked ownable synchronizers:
    - <0x00000000fb344d08> (a java.util.concurrent.locks.ReentrantReadWriteLock$NonfairSync)
    - <0x00000000e0bca828> (a java.util.concurrent.ThreadPoolExecutor$Worker)

@PostConstruct 注解调用 public voidreplicate() 时,它们会陷入僵局。

当它被另一个 bean 调用时,youCantGetMe 会返回。

例如,以下设置有效:

@Startup
@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
public class DeadlockReproducer {
    private final Logger LOGGER = Logger.getInstance(LogCategory.OPENEJB_STARTUP_CONFIG, this.getClass());

    @EJB
    private DeadlockReproducerAid deadlockReproducerAid;

    //@PostConstruct - no postconstruct now
    public  void reproduce(){
        LOGGER.info("reproduce");
        deadlockReproducerAid.lockMe();
    }

    public void youCantGetMe(){
        LOGGER.info("youCantGetMe");
    }
}


@Startup
@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
public class DeadlockReproducerAid {
    private final Logger LOGGER = Logger.getInstance(LogCategory.OPENEJB_STARTUP_CONFIG, this.getClass());

    @EJB
    DeadlockReproducer deadlockReproducer;

    public void lockMe(){
        LOGGER.info("lockMe");
        deadlockReproducer.youCantGetMe();
    }
}


@Startup
@Singleton
public class DeadlockInvoker {

    @EJB
    DeadlockReproducer deadlockReproducer;

    @PostConstruct
    public void startup(){
        deadlockReproducer.reproduce();
    }
}

为什么会这样?我怎样才能让它工作而不诉诸外部调用者的技巧?

编辑:

我开始发现这种行为与 EJB 中的 Singleton 生命周期有关。

@PostConstruct完成运行之前,单例不会进入Ready状态,并且可能当它的状态不是Ready时,它就会进入不响应外部方法调用。

EJB lifecycle

最佳答案

您需要标记您的第一个 ejb 需要第二个 ejb 在它之前启动:https://docs.oracle.com/javaee/6/api/javax/ejb/DependsOn.html

除此之外,我没有发现代码有任何问题,单例使用可重入锁,所以这应该可以工作。

关于java - EJB 两个单例相互调用死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35880204/

相关文章:

java - 使用 Wicket/JPA 注入(inject)实体管理器时出错

java - EJB 实体 : database row is automatically updated from Entity without save in EJB

java - 如何使 eclipse neon 在包 View 中显示 git 分支?

java - 基于传入值的 gRPC 响应头

java - actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS) 弃用

java - com.sun.enterprise.container.common.spi.util.InjectionException : Error creating managed object for class

Java RMI : how InitialContext. Lookup() 有效

objective-c - 这个递归同步调用怎么不死锁呢?

mysql - 在 SELECT … INNER JOIN … FOR UPDATE 的情况下,字符串的顺序会被锁定,以及如何避免死锁?

multithreading - 多线程锁定,有趣的时光(期中练习)