8

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.

skaffman
  • 398,947
  • 96
  • 818
  • 769
Dave Richardson
  • 4,880
  • 7
  • 32
  • 47

4 Answers4

5

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.

Dave Richardson
  • 4,880
  • 7
  • 32
  • 47
5

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.

John M
  • 13,053
  • 3
  • 27
  • 26
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.

Shashi
  • 14,980
  • 2
  • 33
  • 52
2
  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.
Andrey Nudko
  • 697
  • 5
  • 5
  • 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. – Dave Richardson Nov 04 '11 at 09:49
  • Yeah, another thing - if that's part of shutting down the whole app, close the full set of objects (`MessageConsumer`, `Session`, `Connection`). – Andrey Nudko Nov 04 '11 at 10:45
  • 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." – hB0 Mar 21 '22 at 18:14