简体   繁体   中英

Consuming JMS with a multi-threaded client

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM