Chapter 41. 线程管理

本章讲述HornetQ如何使用线程池以及如何管理线程。

首先我们讨论在服务器端线程是如何被管理的,然后我们再讨论客户端的情况。

41.1. 服务器端线程的管理

每个HornetQ服务器都有一个线程池作为一般线程使用,另外还有一个可计划线程池。Java的可计划线程池不能作为 标准的线程池使用,因此我们采用了两个单独的线程池。

当使用旧的(阻塞)IO时,使用了一个单独的线程池来处理连接。但是旧的IO要求一个线程配一个连接,所以如果你 的应用有很多并发的连接,这个线程池会很快用光所有的线程,造成服务器出现“挂起”现象。因此,对于大量并发连接 的应用,一定要使用NIO。

如果使用NIO,默认情况下HornetQ会使用系统中处理器内核(或超线程)数量三倍的线程来处理接收的数据包。 内核的数量是通过调用Runtime.getRuntime().availableProcessors()来得到 的。如果你想改变这个数量,可以设置传输层配置参数nio-remoting-threads。 参见Chapter 16, 传输层的配置

另外在其它一些地方直接使用了线程,没有用线程池。我们将对这些线程作出解释。

41.1.1. 服务器端可计划线程池

服务器可计划线程池可以定期地或延迟地执行所交给的任务,它用来完成HornetQ中绝大部分这样的任务。 它内部使用的是一个 java.util.concurrent.ScheduledThreadPoolExecutor实例。

最大线程数可以在hornetq-configuration.xml文件中进行配置,参数名是scheduled-thread-pool-max-size。默认值是5。 通常这个线程池不需要很大数量的线程。

41.1.2. 服务器通用线程池

服务器端绝大部分的异步操作都是由这个线程池来完成的。在它的内部使用了一个java.util.concurrent.ThreadPoolExecutor的实例。

这个线程池的最大线程数在hornetq-configuration.xml文件中配置,相应的参数名为thread-pool-max-size

如果将参数设为-1则表示该线程池没有线程限制。也就是说当线程不够用时,线程池就 会创建新的线程。当任务不多时,空闲的线程将会超时并被关闭。

如果这个参数的值是一个大于零的整数n,则该线程池的线程数是有限的。当所有线程都 处于忙的状态并且线程数已经达到n时,任何新的请求都将被阻塞直到有线程空闲为止。在设置线程上限时,我们建议 要非常谨慎。因为如何线程数量过低会造成死锁情况的发生。

thread-pool-max-size的默认值是30

参见J2SE javadoc有关无边界(缓存)和有边界(固定)线程池的解释。

41.1.3. 过期回收线程

HornetQ使用一个单独的线程来扫描队列中过期的消息。由于这个线程需要自己的优先级配置,所以不能使用上述的 任何一个线程池。

关于回收线程的配置请参阅Chapter 22, 过期的消息

41.1.4. 异步IO

HornetQ使用一个线程池来进行异步IO的操作,包括事件的接收和发送。这些线程的名字都是以 HornetQ-AIO-poller-pool为开头。每个打开的日志文件都对应有一个线程为其服务(通常只有 一个)。

还有一个单独的线程用于向libaio发送写请求。这样做是为了避免上下文转换带来的性能下降。该 线程的名字以HornetQ-AIO-writer-pool开头。

41.2. 客户端线程管理

在客户端HornetQ有一个静态的可计划线程池和一个静态的通用线程池,它们在一个JVM中由同一个classloader装载的所有客户端 共同使用。

静态的可计划的线程池的最大线程数为 5,通用线程池则没有线程数限制。

如果需要还可以配置一个ClientSessionFactory实例以使它拥有自己的可计划与通用线程池。通过这个工厂创建的会话都 将使用这些线程池。

要想配置ClientSessionFactory使用自己的线程池,只要调用它相应的方法取出可,如:

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

如果使用JMS,你可以先用同样的参数设置ClientSessionFactory,然后再用这样工厂创建ConnectionFactory的实例。如:

ConnectionFactory myConnectionFactory = HornetQJMSClient.createConnectionFactory(myFactory);     

如果你使用JNDI来创建HornetQConnectionFactory 实例,你还可以在hornetq-jms.xml文件中进行配置。如:

<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>