You need to remember:
ConnectionFactory, Connection, Topic and Queue are thread-safe object. You can pass them around different thread without worrying about concurrency issues.
While Session object should be created per thread.
If you use Spring to implement JMS client, instance of the JMSTemplate class is thread-safe. The multi-threading  capability provided by Spring from Message Listener Containers, by creating a fixed number of JMS sessions and consumers at startup.
Therea are 2 types of Message Listener Container, SimpleMessageListenerContainer and DefaultMessageListenerContainer.


<bean id="jmsRequestListenerContainerdefault" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
    <property name="concurrentConsumers" value="1" />
    <property name="maxConcurrentConsumers" value="5" />
    <property name="cacheLevel"      value="0"/>
    <property name="connectionFactory"   ref="queueConnectionFactory" />
    <property name="destination"          ref="customeDestination"/>
    <property name="sessionTransacted"  value="true"/>
    <property name="messageListener" ref="jmsRequestListener" />
    <property name="messageSelector" value="color='RED'"/>


If you have a heavy logic processing the message inside the MessageListener, you can also spawn additional thread within the MessageListener.
// your messageListener
public class MyMessageListener implements MessageListener{

public void onMessage(Message message) {
        TextMessage msg = (TextMessage) message;

        // create a Threadpool with 3 threads
        final ExecutorService executor = Executors.newCachedThreadPool(); 
        executor.submit(new MessageProcessor(msg.getText())); 
        executor.submit(new MessagePublisher(msg.getText())); 
        executor.submit(new MessagePublisher(msg.getText())); 

public class MessageProcessor extends Thread {
    private String message;    

    public MessageProcessor(String message){

    public void run(){
        //your processing logic here