Spring使用ThreadPoolTaskExecutor的默认队列大小是多少?



我正在使用Spring 4.3.8.RELEASE和Java 7。 我想创建一个线程池来执行任务,所以我在我的 Spring contxet 中设置了以下内容

<bean id="myThreadFactory" class="org.springframework.scheduling.concurrent.CustomizableThreadFactory">
<constructor-arg value="mythread-"/>
</bean>
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="threadFactory" ref="myThreadFactory"/>
<property name="corePoolSize" value="10" />
<property name="maxPoolSize" value="50" />
</bean>

为了不降低机器 CPU 使用率,我想限制系统中可以存在的并发线程数量(我假设这就是 maxPOolSize 所做的)。 但我不希望任务被丢弃。 如果我向 taskPoolExecutor 添加超过 50 个任务,第 51 个任务会发生什么情况? 更重要的是,在开始删除任务之前可以添加的默认任务数是多少?

设置maxPoolSize隐式允许删除任务。 但是,默认队列容量是Integer.MAX_VALUE,出于实际目的,它是无穷大。

需要注意的是,ThreadPoolTaskExecutor在下面使用了一个ThreadPoolExecutor,它有一个有点不寻常的排队方法,如文档中所述:

如果正在运行corePoolSize或更多线程,则执行程序始终更喜欢对请求进行排队,而不是添加新线程。

这意味着maxPoolSize仅在队列已满时才相关,否则线程数永远不会超过corePoolSize。 例如,如果我们向线程池提交从未完成的任务:

  • corePoolSize个提交将分别启动一个新线程;
  • 之后,所有提交都将进入队列;
  • 如果队列有限且其容量已耗尽,则每次提交都会启动一个新线程,直到池中maxPoolSize线程;
  • 当池和队列都已满时,新提交将被拒绝。

请注意 ThreadpoolTaskExectuor 中可用的不同队列配置。

任何阻塞队列都可用于传输和保留提交的任务。 此队列的使用与池大小调整交互:如果少于 corePoolSize 线程正在运行,执行器总是喜欢添加一个 新线程而不是排队。如果 corePoolSize 或更多线程是 运行时,执行程序总是更喜欢对请求进行排队,而不是 添加新线程。如果请求无法排队,则新线程 创建,除非这将超过最大池大小,在这种情况下, 任务将被拒绝。

队列有三种常规策略:

  1. 直接交接。 工作队列的一个不错的默认选择是同步队列,它将任务移交给线程,而不保留它们。在这里,如果没有线程立即可用于运行任务,则尝试对任务进行排队将失败,因此将构造一个新线程。此策略可避免在处理可能具有内部依赖项的请求集时锁定。直接交接通常需要无限的最大池大小,以避免拒绝新提交的任务。这反过来又承认当命令继续以平均比处理速度更快的速度到达时,线程无限增长的可能性。
  2. 无限队列 。使用无限队列(例如,没有预定义容量的 LinkedBlockingQueue)将导致当所有 corePoolSize 线程都繁忙时,新任务在队列中等待。因此,不会创建超过corePoolSize的线程。(因此,最大池大小的值没有任何影响。当每个任务完全独立于其他任务时,这可能是合适的,因此任务不能影响彼此的执行;例如,在网页服务器中。虽然这种排队方式在平滑请求的暂时突发方面很有用,但它承认当命令继续以平均快于处理速度到达时,工作队列无限增长的可能性。
  3. 有界队列。 有界队列(例如,ArrayBlockingQueue)在与有限的最大池大小一起使用时有助于防止资源耗尽,但可能更难调整和控制。队列大小和最大池大小可以相互权衡:使用大队列和小池可以最大程度地减少 CPU 使用率、操作系统资源和上下文切换开销,但可能会导致人为的低吞吐量。如果任务经常阻塞(例如,如果它们受 I/O 限制),则系统可能能够为比您允许的线程更多的线程安排时间。使用小型队列通常需要较大的池大小,这使 CPU 更加繁忙,但可能会遇到不可接受的调度开销,这也会降低吞吐量。(我们在多次测试后实现了这种方法,并使用核心池和最大池大小调整队列大小)。

参考 : https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html

如果执行了许多@Async任务,请注意使用默认ThreadPoolTaskExecutor

从 Spring Boot 2.1 开始,有一个默认ThreadPoolTaskExecutor,默认内核大小为 8 个线程。尽管最大池大小仍然是无穷大¹,并且理论上可以创建新线程,但此池的队列大小也是无穷大¹。

队列大小可能永远不会达到,并且永远不会创建新线程。

如果使用@Async,至少设置队列大小:

spring.task.execution.pool.queue-capacity=16

¹ 无穷大,如2147483647又名Integer.MAX_VALUE

相关内容

最新更新