【问题标题】:JMS DefaultMessageListenerContainer not able to shutdown on Spring application context.close()JMS DefaultMessageListenerContainer 无法在 Spring 应用程序 context.close() 上关闭
【发布时间】:2021-04-30 15:50:04
【问题描述】:

我正在使用 Spring 集成收听 Solace 动态主题,如下所示:

<int-jms:message-driven-channel-adapter
    id="myJmsAdapter" channel="receiveChannel" container="jmsContainer" />

<bean id="jmsContainer"
    class="org.springframework.jms.listener.DefaultMessageListenerContainer">
    <property name="connectionFactory" ref="solaceConnectionFactory" />
      <property name="destinationName" value="${my.topic}/#{main.getCar_type_value()}" />
    <property name="pubSubDomain" value="true" />        
    <property name="sessionTransacted" value="false" />
    
</bean>

我能够聆听主题、使用消息并进行处理。 但是在System.exit(0) 上,即使在 ShutdownHook 中关闭了 spring 应用程序上下文,JMS 侦听器线程仍处于挂起状态,无法正常关闭:

ctxt.registerShutdownHook();
...
  trigger = new ShutdownTrigger(maxWaitForResponseMillis, ctxt);
  trigger.startShutdownTimer();

    Runtime.getRuntime().addShutdownHook(new Thread() {
        public void run() {
            log.info("Exiting Main Thread!");
            ctxt.close();
        }
    });

应用程序在超时时正常关闭,但是当我尝试在计时器之前使用 System.exit(0) 从其他类中退出时,它没有关闭并且线程挂起。

定时器功能如下:

   public void startShutdownTimer() {
      timer.schedule(new TimerTask() {
        @Override
        public void run() {
            log.info("Timer max wait has elapsed - triggering graceful 
     shutdown");
            
            // perform some task here on timeout..
            }
            log.info("Returning with exit code: " + exitCode);
            
            System.exit(exitCode); //this one works and it properly shutsdown
        }
    }, maxWaitForResponseMillis);
}

我还尝试在关闭主类的上下文之前添加 Timer.cancel,如下所示,但它不起作用:

     Runtime.getRuntime().addShutdownHook(new Thread() {
    public void run() {
    log.info("Cancelling current timer task..")
        trigger.getTimer().cancel(); //it didnt work and the thread still hangs
        log.info("Exiting Main Thread!");
        ctxt.close();
    }
});

我尝试取出 Timer 函数及其所有引用,以查看是否它的这个计时器线程导致了问题,但没有。即使计时器任务被删除,应用程序也会挂起。

下面是挂起时的线程栈:

"Thread-3" #26 prio=5 os_prio=0 tid=0x00007fcf48024800 nid=0x60ad in Object.wait() [0x00007fd026ef1000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at org.springframework.jms.listener.DefaultMessageListenerContainer.doShutdown(DefaultMessageListenerContainer.java:568)
- locked <0x00000000ee0c9ec0> (a java.lang.Object)
at org.springframework.jms.listener.AbstractJmsListeningContainer.shutdown(AbstractJmsListeningContainer.java:237)

请帮助找出问题和解决方案...

【问题讨论】:

标签: java spring spring-jms jms-topic application-shutdown


【解决方案1】:

您正在侦听器容器线程上调用System.exit()

"jmsContainer-1" #24 prio=5 os_prio=0 tid=0x00007fdbd8e50800 nid=0xb77 in Object.wait() [0x00007fdb9f1bc000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x00000000f02cfb68> (a com.tdsecurities.fxts.vs.FxVsCashBalanceApp$1)
    at java.lang.Thread.join(Thread.java:1245)
    - locked <0x00000000f02cfb68> (a com.tdsecurities.fxts.vs.FxVsCashBalanceApp$1)
    at java.lang.Thread.join(Thread.java:1319)
    at java.lang.ApplicationShutdownHooks.runHooks(ApplicationShutdownHooks.java:106)
    at java.lang.ApplicationShutdownHooks$1.run(ApplicationShutdownHooks.java:46)
    at java.lang.Shutdown.runHooks(Shutdown.java:123)
    at java.lang.Shutdown.sequence(Shutdown.java:167)
    at java.lang.Shutdown.exit(Shutdown.java:212)
    - locked <0x00000000c04335c8> (a java.lang.Class for java.lang.Shutdown)
    at java.lang.Runtime.exit(Runtime.java:109)
    at java.lang.System.exit(System.java:971)

这会导致应用程序上下文(线程 3 和线程 5)死锁(关闭容器)。

您可能需要将System.exit() 调用移交给另一个线程,但我需要知道您使用哪个版本的 Spring 来进一步分析。否则很难关联转储中的行号。

【讨论】:

  • 嗨,加里,感谢您的回复。我正在使用 Spring 4.2.4。我还想补充一点,当应用程序启动时,它还会安排一个 1 小时的计时器任务,以及在应用程序成功处理 JMS 响应后我正在尝试执行的操作,我试图在不等待计时器的情况下退出。我尝试添加 Timer.cancel() 想知道这是否是导致问题的线程,但它没有帮助。我也将使用计时器功能编辑原始帖子。谢谢
  • 如我所说;问题是你在容器线程上调用System.exit(),而容器线程又通过钩子试图关闭容器。顺便说一句,4.2 不再支持; 4.3 也在去年底停止了支持。您应该尽快升级到 5.3。
  • 现在有了正确的行号,我确实可以确认关闭钩子(试图关闭上下文)被阻塞等待侦听器容器线程终止,并且侦听器容器线程被阻塞等待关闭挂钩终止。因此出现了不可恢复的死锁。
  • 谢谢加里。我试图处理退出 JMS 链,仍然挂起。我这里添加了流程:gist.github.com/vathappan/8b17e8dc5cc854319b072fc5b8686bbd请大家看看帮忙
  • 那不会有任何区别;该服务仍在同一线程上处理 - 您需要将 System.exit() 调用移交给另一个线程。
猜你喜欢
  • 2021-04-01
  • 1970-01-01
  • 2014-07-25
  • 1970-01-01
  • 2015-12-24
  • 2017-03-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多