activemq-artemis/docs/user-manual/zh/thread-pooling.xml

109 lines
8.5 KiB
XML
Raw Normal View History

<?xml version="1.0" encoding="UTF-8"?>
<!-- ============================================================================= -->
<!-- Copyright © 2009 Red Hat, Inc. and others. -->
<!-- -->
<!-- The text of and illustrations in this document are licensed by Red Hat under -->
<!-- a Creative Commons AttributionShare Alike 3.0 Unported license ("CC-BY-SA"). -->
<!-- -->
<!-- An explanation of CC-BY-SA is available at -->
<!-- -->
<!-- http://creativecommons.org/licenses/by-sa/3.0/. -->
<!-- -->
<!-- In accordance with CC-BY-SA, if you distribute this document or an adaptation -->
<!-- of it, you must provide the URL for the original version. -->
<!-- -->
<!-- Red Hat, as the licensor of this document, waives the right to enforce, -->
<!-- and agrees not to assert, Section 4d of CC-BY-SA to the fullest extent -->
<!-- permitted by applicable law. -->
<!-- ============================================================================= -->
<chapter id="thread-pooling">
<title>线程管理</title>
<para>本章讲述ActiveMQ如何使用线程池以及如何管理线程。</para>
<para>首先我们讨论在服务器端线程是如何被管理的,然后我们再讨论客户端的情况。</para>
<section>
<title>服务器端线程的管理</title>
<para>每个ActiveMQ服务器都有一个线程池作为一般线程使用另外还有一个可计划线程池。Java的可计划线程池不能作为
标准的线程池使用,因此我们采用了两个单独的线程池。</para>
<para>当使用旧的阻塞IO时使用了一个单独的线程池来处理连接。但是旧的IO要求一个线程配一个连接所以如果你
的应用有很多并发的连接,这个线程池会很快用光所有的线程,造成服务器出现“挂起”现象。因此,对于大量并发连接
的应用一定要使用NIO。</para>
<para>如果使用NIO默认情况下ActiveMQ会使用系统中处理器内核或超线程数量三倍的线程来处理接收的数据包。
内核的数量是通过调用<literal>Runtime.getRuntime().availableProcessors()</literal>来得到
的。如果你想改变这个数量,可以设置传输层配置参数<literal>nio-remoting-threads</literal>
参见<xref linkend="configuring-transports"/></para>
<para>另外在其它一些地方直接使用了线程,没有用线程池。我们将对这些线程作出解释。</para>
<section id="server.scheduled.thread.pool">
<title>服务器端可计划线程池</title>
<para>服务器可计划线程池可以定期地或延迟地执行所交给的任务它用来完成ActiveMQ中绝大部分这样的任务。
它内部使用的是一个 <literal
>java.util.concurrent.ScheduledThreadPoolExecutor</literal>实例。</para>
<para>最大线程数可以在<literal
>activemq-configuration.xml</literal>文件中进行配置,参数名是<literal
>scheduled-thread-pool-max-size</literal>。默认值是<literal>5</literal>
通常这个线程池不需要很大数量的线程。</para>
</section>
<section>
<title>服务器通用线程池</title>
<para>服务器端绝大部分的异步操作都是由这个线程池来完成的。在它的内部使用了一个<literal
>java.util.concurrent.ThreadPoolExecutor</literal>的实例。</para>
<para>这个线程池的最大线程数在<literal>activemq-configuration.xml</literal>文件中配置,相应的参数名为<literal
>thread-pool-max-size</literal></para>
<para>如果将参数设为<literal>-1</literal>则表示该线程池没有线程限制。也就是说当线程不够用时,线程池就
会创建新的线程。当任务不多时,空闲的线程将会超时并被关闭。</para>
<para>如果这个参数的值是一个大于零的整数<literal>n</literal>,则该线程池的线程数是有限的。当所有线程都
处于忙的状态并且线程数已经达到n时任何新的请求都将被阻塞直到有线程空闲为止。在设置线程上限时我们建议
要非常谨慎。因为如何线程数量过低会造成死锁情况的发生。</para>
<para><literal>thread-pool-max-size</literal>的默认值是<literal
>30</literal></para>
<para>参见<ulink
url="http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/ThreadPoolExecutor.html"
>J2SE javadoc</ulink>有关无边界(缓存)和有边界(固定)线程池的解释。</para>
</section>
<section>
<title>过期回收线程</title>
<para>ActiveMQ使用一个单独的线程来扫描队列中过期的消息。由于这个线程需要自己的优先级配置所以不能使用上述的
任何一个线程池。</para>
<para>关于回收线程的配置请参阅<xref linkend="message-expiry"/></para>
</section>
<section>
<title>异步IO</title>
<para>ActiveMQ使用一个线程池来进行异步IO的操作包括事件的接收和发送。这些线程的名字都是以
ActiveMQ-AIO-poller-pool为开头。每个打开的日志文件都对应有一个线程为其服务通常只有
一个)。</para>
<para>还有一个单独的线程用于向libaio发送写请求。这样做是为了避免上下文转换带来的性能下降。该
线程的名字以ActiveMQ-AIO-writer-pool开头。</para>
</section>
</section>
<section id="thread-pooling.client.side">
<title>客户端线程管理</title>
<para>在客户端ActiveMQ有一个静态的可计划线程池和一个静态的通用线程池它们在一个JVM中由同一个classloader装载的所有客户端
共同使用。</para>
<para>静态的可计划的线程池的最大线程数为 <literal>5</literal>,通用线程池则没有线程数限制。</para>
<para>如果需要还可以配置一个<literal
>ClientSessionFactory</literal>实例以使它拥有自己的可计划与通用线程池。通过这个工厂创建的会话都
将使用这些线程池。</para>
<para>要想配置<literal>ClientSessionFactory</literal>使用自己的线程池,只要调用它相应的方法取出可,如:</para>
<programlisting>ClientSessionFactory myFactory = ActiveMQClient.createClientSessionFactory(...);
myFactory.setUseGlobalPools(false);
myFactory.setScheduledThreadPoolMaxSize(10);
myFactory.setThreadPoolMaxSize(-1); </programlisting>
<para>如果使用JMS你可以先用同样的参数设置ClientSessionFactory然后再用这样工厂创建<literal
>ConnectionFactory</literal>的实例。如:</para>
<programlisting>ConnectionFactory myConnectionFactory = ActiveMQJMSClient.createConnectionFactory(myFactory); </programlisting>
<para>如果你使用JNDI来创建<literal>ActiveMQConnectionFactory</literal>
实例,你还可以在<literal>hornetq-jms.xml</literal>文件中进行配置。如:</para>
<programlisting>&lt;connection-factory name="ConnectionFactory"&gt;
&lt;connectors>
&lt;connector-ref connector-name="netty"/&gt;
&lt;/connectors>
&lt;entries&gt;
&lt;entry name="ConnectionFactory"/&gt;
&lt;entry name="XAConnectionFactory"/&gt;
&lt;/entries&gt;
&lt;use-global-pools&gt;false&lt;/use-global-pools&gt;
&lt;scheduled-thread-pool-max-size&gt;10&lt;/scheduled-thread-pool-max-size&gt;
&lt;thread-pool-max-size&gt;-1&lt;/thread-pool-max-size&gt;
&lt;/connection-factory&gt;</programlisting>
</section>
</chapter>