JBoss.orgCommunity Documentation
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.
When using old (blocking) IO, a separate thread pool is also used to service connections. Since old IO requires a thread per connection it does not make sense to get them from the standard pool as the pool will easily get exhausted if too many connections are made, resulting in the server "hanging" since it has no remaining threads to do anything else. If you require the server to handle many concurrent connections you should make sure you use NIO, not old IO.
When using new IO (NIO), HornetQ will, by default, use a number of threads equal to
three times the number of cores (or hyper-threads) as reported by
Runtime.getRuntime().availableProcessors() for processing incoming packets. If you want
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.
The server scheduled thread pool is used for most activities on the server side
that require running periodically or with delays. It maps internally to a java.util.concurrent.ScheduledThreadPoolExecutor
instance.
The maximum number of thread used by this pool is configure in hornetq-configuration.xml
with the scheduled-thread-pool-max-size
parameter. The default value is
5
threads. A small number of threads is usually sufficient
for this pool.
This general purpose thread pool is used for most asynchronous actions on the
server side. It maps internally to a java.util.concurrent.ThreadPoolExecutor
instance.
The maximum number of thread used by this pool is configure in hornetq-configuration.xml
with the thread-pool-max-size
parameter.
If a value of -1
is used this signifies that the thread pool
has no upper bound and new threads will be created on demand if there are not enough
threads available to satisfy a request. If activity later subsides then threads are
timed-out and closed.
If a value of n
where n
is a positive integer
greater than zero is used this signifies that the thread pool is bounded. If more
requests come in and there are no free threads in the pool and the pool is full then
requests will block until a thread becomes available. It is recommended that a
bounded thread pool is used with caution since it can lead to dead-lock situations
if the upper bound is chosen to be too low.
The default value for thread-pool-max-size
is 30
.
See the J2SE javadoc for more information on unbounded (cached), and bounded (fixed) thread pools.
A single thread is also used on the server side to scan for expired messages in queues. We cannot use either of the thread pools for this since this thread needs to run at its own configurable priority.
For more information on configuring the reaper, please see Chapter 22, Message Expiry.
Asynchronous IO has a thread pool for receiving and dispatching events out of the native layer. You will find it on a thread dump with the prefix HornetQ-AIO-poller-pool. HornetQ uses one thread per opened file on the journal (there is usually one).
There is also a single thread used to invoke writes on libaio. We do that to avoid context switching on libaio that would cause performance issues. You will find this thread on a thread dump with the prefix HornetQ-AIO-writer-pool.
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>