JBoss.orgCommunity Documentation

Chapter 41. Thread management

41.1. Server-Side Thread Management
41.1.1. Server Scheduled Thread Pool
41.1.2. General Purpose Server Thread Pool
41.1.3. Expiry Reaper Thread
41.1.4. Asynchronous IO
41.2. Client-Side Thread Management

This chapter describes how HornetQ uses and pools threads and how you can manage them.

First we'll discuss how threads are managed and used on the server side, then we'll look at the client side.

Each HornetQ Server maintains a single thread pool for general use, and a scheduled thread pool for scheduled use. A Java scheduled thread pool cannot be configured to use a standard thread pool, otherwise we could use a single thread pool for both scheduled and non scheduled activity.

A separate thread pool is also used to service connections. HornetQ can use "old" (blocking) IO or "new" (non-blocking) IO also called NIO. Both of these options use a separate thread pool, but each of them behaves uniquely.

Since old IO requires a thread per connection its thread pool is unbounded. The thread pool is created via java.util.concurrent.Executors.newCachedThreadPool(ThreadFactory). As the JavaDoc for this method states: “Creates a thread pool that creates new threads as needed, but will reuse previously constructed threads when they are available, and uses the provided ThreadFactory to create new threads when needed.” Threads from this pool which are idle for more than 60 seconds will time out and be removed. If old IO connections were serviced from the standard pool the pool would easily get exhausted if too many connections were made, resulting in the server "hanging" since it has no remaining threads to do anything else. However, even an unbounded thread pool can run into trouble if it becomes too large. If you require the server to handle many concurrent connections you should use NIO, not old IO.

When using new IO (NIO), HornetQ will, by default, cap its thread pool at three times the number of cores (or hyper-threads) as reported by Runtime.getRuntime().availableProcessors() for processing incoming packets. To override this value, you can set the number of threads by specifying the parameter nio-remoting-threads in the transport configuration. See the Chapter 16, Configuring the Transport for more information on this.

There are also a small number of other places where threads are used directly, we'll discuss each in turn.

On the client side, HornetQ maintains a single static scheduled thread pool and a single static general thread pool for use by all clients using the same classloader in that JVM instance.

The static scheduled thread pool has a maximum size of 5 threads, and the general purpose thread pool has an unbounded maximum size.

If required HornetQ can also be configured so that each ClientSessionFactory instance does not use these static pools but instead maintains its own scheduled and general purpose pool. Any sessions created from that ClientSessionFactory will use those pools instead.

To configure a ClientSessionFactory instance to use its own pools, simply use the appropriate setter methods immediately after creation, for example:

ServerLocator locator = HornetQClient.createServerLocatorWithoutHA(...)
ClientSessionFactory myFactory = locator.createClientSessionFactory();
myFactory.setUseGlobalPools(false);
myFactory.setScheduledThreadPoolMaxSize(10);
myFactory.setThreadPoolMaxSize(-1);   

If you're using the JMS API, you can set the same parameters on the ClientSessionFactory and use it to create the ConnectionFactory instance, for example:

ConnectionFactory myConnectionFactory = HornetQJMSClient.createConnectionFactory(myFactory);

If you're using JNDI to instantiate HornetQConnectionFactory instances, you can also set these parameters in the hornetq-jms.xml file where you describe your connection factory, for example:

<connection-factory name="ConnectionFactory">
   <connectors>
      <connector-ref connector-name="netty"/>
   </connectors>
   <entries>
      <entry name="ConnectionFactory"/>
      <entry name="XAConnectionFactory"/>
   </entries>
   <use-global-pools>false</use-global-pools>
   <scheduled-thread-pool-max-size>10</scheduled-thread-pool-max-size>
   <thread-pool-max-size>-1</thread-pool-max-size>
</connection-factory>