javax.jms.MessageConsumer hangs on receive when consumer closed

18,407

Solution 1

I've sorted the problem, I wasn't doing a connection.start() anywhere. Once I put this in, the MessageConsumer.receive() stopped blocking when I closed it and everything worked as I had expected.

Thanks for your suggestions.

Solution 2

One further thought.

In JMS, Connection is multi-threaded. Session and below (Consumer, Producer, Message, etc) are not thread-safe. If you're accessing any of that non-thread-safe stuff from multiple threads, you're responsible for avoiding multi-threaded access.

The code you show below looks like you're calling methods on Consumer from a couple of threads. A violation of that rule.

It might be safer to just close the Connection object. No threading conflicts and any sensible implementation would do the right thing to clean up resources associated w/ the Connection.

Solution 3

But still, calling consumer.close() on another thread is not the right thing to do. You will need to do a connection.Close which will take care of closing all sessions, consumers, producers etc under that connection.

Solution 4

  1. Try receive(long timeout), and don't forget to to check that returned mesage is not null.
  2. In addition to consumer.close() you may also interrupt polling thread - if close() is implemented poorly and doesn't notify blocked receiver, this will wake it up.
Share:
18,407
Dave Richardson
Author by

Dave Richardson

Me: a name I call myself.

Updated on June 05, 2022

Comments

  • Dave Richardson
    Dave Richardson about 2 years

    According to the javadoc, if I call receive() on a javax.jms.MessageConsumer it will block indefinitely until a message is produced or until the message consumer is closed.

    I have a thread in which a receive() is being called. As part of the thread shutdown I am calling close(), but the consumer still blocks in receive() and so the thread will not shutdown. The gist of my code is:

    public String receiveMessage() {
    ...
    ...
       System.out.println("About to receive")
       TextMessage message = (TextMessage) consumer.receive();
       System.out.println("No longer receiving")
    ...
    ...
    }
    
    public void stop() {
        try {
            if (consumer != null) {
                consumer.close();
            }
        } catch (JMSException ex) {
            throw new IllegalStateException(ex);
        }
    }
    

    In the debugger I can see close() being called, but the receive still blocks. If I use the receive() method with a timeout it will block until the timeout expires.

    Everything looks right to me, hopefully someone can tell me what I am doing wrong.

  • Dave Richardson
    Dave Richardson over 12 years
    Thanks for this. I've tried the timeout version of receive() and I have the same problem - it just blocks for the remainder of the timeout and so my app won't close down until the timeout is complete, which is not quite what I want.
  • Andrey Nudko
    Andrey Nudko over 12 years
    Yeah, another thing - if that's part of shutting down the whole app, close the full set of objects (MessageConsumer, Session, Connection).
  • hB0
    hB0 over 2 years
    But @Shashi above mentioned: "You will need to do a connection.Close which will take care of closing all sessions, consumers, producers etc under that connection."