glassfish
  1. glassfish
  2. GLASSFISH-20836

MessageConsumer.receive() doesn't return when another thread calls MessageConsumer.close().

    Details

    • Type: Bug Bug
    • Status: Open
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: 4.0
    • Fix Version/s: None
    • Component/s: None
    • Labels:
      None

      Description

      The Javadoc for MessageConsumer.receive() reads:

      [...] This call blocks indefinitely until a message is produced or until this message consumer is closed. [...]

      However, it doesn't do that, not even if the thread calling MessageConsumer.receive() is interrupted. This causes my application to hang indefinitely.

        Activity

        Hide
        Christian Schlichtherle added a comment -

        For comparison, ActiveMQ 5.8.0 behaves as described in the Javadoc.

        Show
        Christian Schlichtherle added a comment - For comparison, ActiveMQ 5.8.0 behaves as described in the Javadoc.
        Hide
        Christian Schlichtherle added a comment -

        Meanwhile, I tried to close the MessageConsumer, the Session and the Connection, but nothing makes MessageConsumer.receive() return. I even tried MessageConsumer.receive(Long.MAX_VALUE), hoping it would be implemented to respect the contract, but no, that doesn't help at all.

        Show
        Christian Schlichtherle added a comment - Meanwhile, I tried to close the MessageConsumer, the Session and the Connection, but nothing makes MessageConsumer.receive() return. I even tried MessageConsumer.receive(Long.MAX_VALUE), hoping it would be implemented to respect the contract, but no, that doesn't help at all.
        Hide
        Christian Schlichtherle added a comment -

        If I try to call Session.close() in order to make MessageConsumer.close() return, then I get a dead lock. Here are the relevant stack traces:

        
        2013-10-02 09:19:52
        
        "TrueUpdate Manager JMS / Receiver" - Thread t@147
           java.lang.Thread.State: WAITING
        	at java.lang.Object.wait(Native Method)
        	- waiting on <5c007408> (a com.sun.messaging.jmq.jmsserver.core.ConsumerUID)
        	at com.sun.messaging.jmq.jmsserver.service.imq.SessionListener.getNextConsumerPacket(IMQDirectService.java:2807)
        	at com.sun.messaging.jmq.jmsserver.service.imq.IMQDirectService.fetchMessage(IMQDirectService.java:2038)
        	at com.sun.messaging.jms.ra.DirectSession._fetchMessage(DirectSession.java:2072)
        	- locked <795cac09> (a com.sun.messaging.jms.ra.DirectTransactionManagedSession)
        	at com.sun.messaging.jms.ra.DirectConsumer.receive(DirectConsumer.java:268)
        	at net.java.trueupdate.jms.JmsReceiver.run(JmsReceiver.java:81)
        	at java.lang.Thread.run(Thread.java:724)
        
           Locked ownable synchronizers:
        	- None
        
        "admin-listener(2)" - Thread t@36
           java.lang.Thread.State: BLOCKED
        	at com.sun.messaging.jms.ra.DirectSession.close(DirectSession.java:256)
        	- waiting to lock <795cac09> (a com.sun.messaging.jms.ra.DirectTransactionManagedSession) owned by "TrueUpdate Manager JMS / Receiver" t@147
        	at net.java.trueupdate.jms.JmsReceiver.stop(JmsReceiver.java:119)
        	- locked <582ae431> (a java.lang.Object)
        	at net.java.trueupdate.manager.jms.JmsUpdateManagerContext.stop(JmsUpdateManagerContext.java:67)
        	at net.java.trueupdate.manager.ejb.UpdateManagerControllerBean.preDestroy(UpdateManagerControllerBean.java:52)
        	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        	at java.lang.reflect.Method.invoke(Method.java:606)
        	at com.sun.ejb.containers.interceptors.BeanCallbackInterceptor.intercept(InterceptorManager.java:1035)
        	at com.sun.ejb.containers.interceptors.CallbackChainImpl.invokeNext(CallbackChainImpl.java:72)
        	at com.sun.ejb.containers.interceptors.CallbackInvocationContext.proceed(CallbackInvocationContext.java:205)
        	at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.doCall(SystemInterceptorProxy.java:163)
        	at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.destroy(SystemInterceptorProxy.java:130)
        	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        	at java.lang.reflect.Method.invoke(Method.java:606)
        	at com.sun.ejb.containers.interceptors.CallbackInterceptor.intercept(InterceptorManager.java:986)
        	at com.sun.ejb.containers.interceptors.CallbackChainImpl.invokeNext(CallbackChainImpl.java:72)
        	at com.sun.ejb.containers.interceptors.InterceptorManager.intercept(InterceptorManager.java:412)
        	at com.sun.ejb.containers.interceptors.InterceptorManager.intercept(InterceptorManager.java:375)
        	at com.sun.ejb.containers.BaseContainer.intercept(BaseContainer.java:1949)
        	at com.sun.ejb.containers.AbstractSingletonContainer$SingletonContextFactory.destroy(AbstractSingletonContainer.java:688)
        	at com.sun.ejb.containers.AbstractSingletonContainer.doConcreteContainerShutdown(AbstractSingletonContainer.java:599)
        	at com.sun.ejb.containers.BaseContainer.onShutdown(BaseContainer.java:4197)
        	at org.glassfish.ejb.startup.SingletonLifeCycleManager.doShutdown(SingletonLifeCycleManager.java:172)
        	at org.glassfish.ejb.startup.EjbApplication.stop(EjbApplication.java:293)
        	at org.glassfish.internal.data.EngineRef.stop(EngineRef.java:161)
        	at org.glassfish.internal.data.ModuleInfo.stop(ModuleInfo.java:324)
        	- locked <1b413af4> (a org.glassfish.internal.data.ModuleInfo)
        	at org.glassfish.internal.data.ApplicationInfo.stop(ApplicationInfo.java:380)
        	at com.sun.enterprise.v3.server.ApplicationLifecycle.unload(ApplicationLifecycle.java:1056)
        	at com.sun.enterprise.v3.server.ApplicationLifecycle.disable(ApplicationLifecycle.java:2125)
        	at com.sun.enterprise.v3.server.ApplicationLifecycle.disable(ApplicationLifecycle.java:113)
        	at org.glassfish.deployment.admin.DisableCommand.execute(DisableCommand.java:378)
        	at com.sun.enterprise.v3.admin.CommandRunnerImpl$2$1.run(CommandRunnerImpl.java:527)
        	at com.sun.enterprise.v3.admin.CommandRunnerImpl$2$1.run(CommandRunnerImpl.java:523)
        	at java.security.AccessController.doPrivileged(Native Method)
        	at javax.security.auth.Subject.doAs(Subject.java:356)
        	at com.sun.enterprise.v3.admin.CommandRunnerImpl$2.execute(CommandRunnerImpl.java:522)
        	at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:546)
        	at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:1423)
        	at com.sun.enterprise.v3.admin.CommandRunnerImpl.access$1500(CommandRunnerImpl.java:108)
        	at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1762)
        	at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1674)
        	at com.sun.enterprise.v3.admin.AdminAdapter.doCommand(AdminAdapter.java:534)
        	at com.sun.enterprise.v3.admin.AdminAdapter.onMissingResource(AdminAdapter.java:224)
        	at org.glassfish.grizzly.http.server.StaticHttpHandler.service(StaticHttpHandler.java:297)
        	at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:246)
        	at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:191)
        	at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:168)
        	at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:189)
        	at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
        	at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:288)
        	at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:206)
        	at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:136)
        	at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:114)
        	at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
        	at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:838)
        	at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:113)
        	at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:115)
        	at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:55)
        	at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:135)
        	at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:564)
        	at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:544)
        	at java.lang.Thread.run(Thread.java:724)
        
           Locked ownable synchronizers:
        	- None
        
        
        Show
        Christian Schlichtherle added a comment - If I try to call Session.close() in order to make MessageConsumer.close() return, then I get a dead lock. Here are the relevant stack traces: 2013-10-02 09:19:52 "TrueUpdate Manager JMS / Receiver" - Thread t@147 java.lang. Thread .State: WAITING at java.lang. Object .wait(Native Method) - waiting on <5c007408> (a com.sun.messaging.jmq.jmsserver.core.ConsumerUID) at com.sun.messaging.jmq.jmsserver.service.imq.SessionListener.getNextConsumerPacket(IMQDirectService.java:2807) at com.sun.messaging.jmq.jmsserver.service.imq.IMQDirectService.fetchMessage(IMQDirectService.java:2038) at com.sun.messaging.jms.ra.DirectSession._fetchMessage(DirectSession.java:2072) - locked <795cac09> (a com.sun.messaging.jms.ra.DirectTransactionManagedSession) at com.sun.messaging.jms.ra.DirectConsumer.receive(DirectConsumer.java:268) at net.java.trueupdate.jms.JmsReceiver.run(JmsReceiver.java:81) at java.lang. Thread .run( Thread .java:724) Locked ownable synchronizers: - None "admin-listener(2)" - Thread t@36 java.lang. Thread .State: BLOCKED at com.sun.messaging.jms.ra.DirectSession.close(DirectSession.java:256) - waiting to lock <795cac09> (a com.sun.messaging.jms.ra.DirectTransactionManagedSession) owned by "TrueUpdate Manager JMS / Receiver" t@147 at net.java.trueupdate.jms.JmsReceiver.stop(JmsReceiver.java:119) - locked <582ae431> (a java.lang. Object ) at net.java.trueupdate.manager.jms.JmsUpdateManagerContext.stop(JmsUpdateManagerContext.java:67) at net.java.trueupdate.manager.ejb.UpdateManagerControllerBean.preDestroy(UpdateManagerControllerBean.java:52) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at com.sun.ejb.containers.interceptors.BeanCallbackInterceptor.intercept(InterceptorManager.java:1035) at com.sun.ejb.containers.interceptors.CallbackChainImpl.invokeNext(CallbackChainImpl.java:72) at com.sun.ejb.containers.interceptors.CallbackInvocationContext.proceed(CallbackInvocationContext.java:205) at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.doCall(SystemInterceptorProxy.java:163) at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.destroy(SystemInterceptorProxy.java:130) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at com.sun.ejb.containers.interceptors.CallbackInterceptor.intercept(InterceptorManager.java:986) at com.sun.ejb.containers.interceptors.CallbackChainImpl.invokeNext(CallbackChainImpl.java:72) at com.sun.ejb.containers.interceptors.InterceptorManager.intercept(InterceptorManager.java:412) at com.sun.ejb.containers.interceptors.InterceptorManager.intercept(InterceptorManager.java:375) at com.sun.ejb.containers.BaseContainer.intercept(BaseContainer.java:1949) at com.sun.ejb.containers.AbstractSingletonContainer$SingletonContextFactory.destroy(AbstractSingletonContainer.java:688) at com.sun.ejb.containers.AbstractSingletonContainer.doConcreteContainerShutdown(AbstractSingletonContainer.java:599) at com.sun.ejb.containers.BaseContainer.onShutdown(BaseContainer.java:4197) at org.glassfish.ejb.startup.SingletonLifeCycleManager.doShutdown(SingletonLifeCycleManager.java:172) at org.glassfish.ejb.startup.EjbApplication.stop(EjbApplication.java:293) at org.glassfish.internal.data.EngineRef.stop(EngineRef.java:161) at org.glassfish.internal.data.ModuleInfo.stop(ModuleInfo.java:324) - locked <1b413af4> (a org.glassfish.internal.data.ModuleInfo) at org.glassfish.internal.data.ApplicationInfo.stop(ApplicationInfo.java:380) at com.sun.enterprise.v3.server.ApplicationLifecycle.unload(ApplicationLifecycle.java:1056) at com.sun.enterprise.v3.server.ApplicationLifecycle.disable(ApplicationLifecycle.java:2125) at com.sun.enterprise.v3.server.ApplicationLifecycle.disable(ApplicationLifecycle.java:113) at org.glassfish.deployment.admin.DisableCommand.execute(DisableCommand.java:378) at com.sun.enterprise.v3.admin.CommandRunnerImpl$2$1.run(CommandRunnerImpl.java:527) at com.sun.enterprise.v3.admin.CommandRunnerImpl$2$1.run(CommandRunnerImpl.java:523) at java.security.AccessController.doPrivileged(Native Method) at javax.security.auth.Subject.doAs(Subject.java:356) at com.sun.enterprise.v3.admin.CommandRunnerImpl$2.execute(CommandRunnerImpl.java:522) at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:546) at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:1423) at com.sun.enterprise.v3.admin.CommandRunnerImpl.access$1500(CommandRunnerImpl.java:108) at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1762) at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1674) at com.sun.enterprise.v3.admin.AdminAdapter.doCommand(AdminAdapter.java:534) at com.sun.enterprise.v3.admin.AdminAdapter.onMissingResource(AdminAdapter.java:224) at org.glassfish.grizzly.http.server.StaticHttpHandler.service(StaticHttpHandler.java:297) at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:246) at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:191) at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:168) at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:189) at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119) at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:288) at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:206) at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:136) at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:114) at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77) at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:838) at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:113) at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:115) at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:55) at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:135) at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:564) at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:544) at java.lang. Thread .run( Thread .java:724) Locked ownable synchronizers: - None
        Hide
        Christian Schlichtherle added a comment -

        Same applies if I call Connection.close() first. So apparently, there is no workaround to make MessageConsumer.receive() return with a null message. This makes me consider this bug a show stopper.

        Show
        Christian Schlichtherle added a comment - Same applies if I call Connection.close() first. So apparently, there is no workaround to make MessageConsumer.receive() return with a null message. This makes me consider this bug a show stopper.
        Hide
        Christian Schlichtherle added a comment -

        Seems like I found a workaround at last: I need to call Connection.close(), which will block indefinitely. So before doing that, I need to create a third thread which interrupts the thread calling MessageConsumer.receive() in a loop until it returns from that method. Here's some code:

        new Thread() {
            @SuppressWarnings("SleepWhileInLoop")
            @Override public void run() {
                for (Thread t; null != (t = thread); ) {
                    t.interrupt();
                    try { Thread.sleep(100); }
                    catch (InterruptedException ex) { }
                }
            }
        }.start();
        

        thread is a volatile field which references the thread calling MessageConsumer.receive(). Once this method returns, it's thread needs to execute thread = null in order to stop the third thread from interrupting it and terminate.

        Show
        Christian Schlichtherle added a comment - Seems like I found a workaround at last: I need to call Connection.close() , which will block indefinitely. So before doing that, I need to create a third thread which interrupts the thread calling MessageConsumer.receive() in a loop until it returns from that method. Here's some code: new Thread () { @SuppressWarnings( "SleepWhileInLoop" ) @Override public void run() { for ( Thread t; null != (t = thread); ) { t.interrupt(); try { Thread .sleep(100); } catch (InterruptedException ex) { } } } }.start(); thread is a volatile field which references the thread calling MessageConsumer.receive() . Once this method returns, it's thread needs to execute thread = null in order to stop the third thread from interrupting it and terminate.
        Hide
        Christian Schlichtherle added a comment -

        Forgot to mention: MessageConsumer.receive() seems to need two interrupts before it returns. This is why I call Thread.interrupt() in a loop.

        Show
        Christian Schlichtherle added a comment - Forgot to mention: MessageConsumer.receive() seems to need two interrupts before it returns. This is why I call Thread.interrupt() in a loop.

          People

          • Assignee:
            michael.y.chen
            Reporter:
            Christian Schlichtherle
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated: