Reputation: 13
I am trying to use multiple threads to consume jms queue. I know that there should be a separate JMS Session for each Thread and that what I did in my code as shown below. But I am getting a weird exception
here is the exception stack trace:
javax.jms.IllegalStateException: Forbidden call on a closed connection.
at org.objectweb.joram.client.jms.Connection.checkClosed(Connection.java:404)
at org.objectweb.joram.client.jms.Connection.createSession(Connection.java:530)
at MessageWorker.run(ReceiveJmsDemoMultiThreaded.java:96)
at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
I need your help because this is a blocking issue for me
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.QueueConnectionFactory;
import javax.jms.Session;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class ReceiveJmsDemoMultiThreaded {
public static void main(String[] args) {
Context context = null;
ConnectionFactory factory = null;
Connection connection = null;
Destination destination = null;
try {
context = getInitialContext();
factory = (QueueConnectionFactory) context.lookup("JQCF");
destination = (Destination) context.lookup("sampleQueue");
connection = factory.createConnection();
final ExecutorService executor = Executors.newCachedThreadPool();
executor.submit(new MessageWorker(connection, destination) );
executor.submit(new MessageWorker(connection, destination) );
executor.submit(new MessageWorker(connection, destination) );
executor.submit(new MessageWorker(connection, destination) );
connection.start();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (context != null) {
try {
context.close();
} catch (NamingException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
}
}
private static InitialContext getInitialContext() throws NamingException {
Properties prop = new Properties();
prop.put("java.naming.provider.url", "rmi://localhost:1099");
prop.put("java.naming.factory.initial",
"org.objectweb.carol.jndi.spi.MultiOrbInitialContextFactory");
return new InitialContext(prop);
}
}
class MessageWorker extends Thread {
Connection connection = null;
Destination dest = null;
Session session = null;
Destination destination = null;
public MessageWorker(Connection connection, Destination dest) {
this.connection = connection;
this.destination = dest;
}
@Override
public void run() {
try {
MessageConsumer receiver = null;
System.out.println("Starting Thread "+currentThread().getName());
while (true) {
try {
System.out.println("Waiting for next msg "+currentThread().getName());
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
receiver = session.createConsumer(destination);
Message msg = receiver.receive();
if (msg instanceof Message && msg != null) {
System.out.println("STARTING consuming "+msg.toString()+" by thread "+currentThread().getName() );
Thread.sleep(2000);//some work here
System.out.println("ENDING consuming "+msg.toString()+" by thread "+currentThread().getName() );
}
} catch (JMSException e) {
e.printStackTrace();
System.exit(1);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}
}
Many thanks
Upvotes: 1
Views: 7930
Reputation: 2841
You are seeing this problem because, in the main thread, after submitting the jobs to the Executor Service, the connection is closed using:
connection.close();
So, when the threads try to create a Session using this shared connection (which just got closed), they are getting this exception. Nothing unexpected here. Just for testing, you can make your main thread sleep for a long time until all your threads are done receiving messages. This way, you can confirm that you dont receive this exception.
A real solution may be to shutdown the Executor service and make the main thread awaitTermination()
to wait for completion of the submitted jobs.
Upvotes: 2