本章介绍 Apache ActiveMQ Artemis 如何使用和池化线程,以及如何管理它们。

首先,我们将讨论线程在服务器端的管理和使用,然后我们将研究客户端。

1. 服务器端线程管理

每个 Apache ActiveMQ Artemis 服务器维护一个用于一般用途的线程池,以及一个用于计划用途的计划线程池。Java 计划线程池无法配置为使用标准线程池,否则我们可以使用一个线程池来处理计划和非计划活动。

默认情况下,Apache ActiveMQ Artemis 会将线程池限制为 `Runtime.getRuntime().availableProcessors()` 报告的核心(或超线程)数量的三倍,用于处理传入数据包。要覆盖此值,您可以通过在传输配置中指定参数 `nioRemotingThreads` 来设置线程数。有关此内容的更多信息,请参阅 配置传输

还有一些其他地方直接使用线程,我们将逐一讨论。

1.1. 服务器计划线程池

服务器计划线程池用于服务器端大多数需要定期运行或延迟运行的活动。它在内部映射到一个 `java.util.concurrent.ScheduledThreadPoolExecutor` 实例。

此池使用的最大线程数在 `broker.xml` 中通过 `scheduled-thread-pool-max-size` 参数配置。默认值为 `5` 个线程。对于此池来说,少量线程通常就足够了。

1.2. 通用服务器线程池

此通用线程池用于服务器端大多数异步操作。它在内部映射到一个 `java.util.concurrent.ThreadPoolExecutor` 实例。

此池使用的最大线程数在 `broker.xml` 中通过 `thread-pool-max-size` 参数配置。

如果使用 `-1` 值,则表示线程池没有上限,并且如果可用的线程不足以满足请求,则会根据需要创建新线程。如果活动之后下降,则线程会超时并关闭。

如果使用 `n` 值,其中 `n` 是大于零的正整数,则表示线程池是有界的。如果收到更多请求,并且池中没有空闲线程,并且池已满,则请求将阻塞,直到有线程可用。建议谨慎使用有界线程池,因为如果上限设置过低,会导致死锁情况。

`thread-pool-max-size` 的默认值为 `30`。

有关无界(缓存)和有界(固定)线程池的更多信息,请参阅 J2SE 文档

1.3. 过期清理线程

服务器端还有一个单线程用于扫描队列中过期的消息。我们无法使用这两个线程池,因为此线程需要以其自己的可配置优先级运行。

有关配置清理器的更多信息,请参阅 消息过期

1.4. 异步 IO

异步 IO 具有一个线程池,用于接收和调度来自本机层的事件。您会在线程转储中找到它,前缀为 ActiveMQ-AIO-poller-pool。Apache ActiveMQ Artemis 在日志文件(通常只有一个)上为每个打开的文件使用一个线程。

还有一个单线程用于在 libaio 上调用写入。我们这样做是为了避免 libaio 上的上下文切换,这会导致性能问题。您会在线程转储中找到此线程,前缀为 ActiveMQ-AIO-writer-pool。

2. 客户端线程管理

在客户端,Apache ActiveMQ Artemis 维护一个单一的“全局”静态计划线程池,以及一个单一的“全局”静态通用线程池,供使用相同类加载器的 JVM 实例中的所有客户端使用。

静态计划线程池的默认最大大小为 `5` 个线程。这可以使用 `scheduledThreadPoolMaxSize` URI 参数更改。

通用线程池的无界最大大小。这可以使用 `threadPoolMaxSize` URL 参数更改。

如果需要,Apache ActiveMQ Artemis 也可以配置为每个 `ClientSessionFactory` 实例不使用这些“全局”静态池,而是维护自己的计划和通用池。从该 `ClientSessionFactory` 创建的任何会话将使用这些池。这使用 `useGlobalPools` 布尔 URL 参数配置。