Spring 的 ThreadPoolTask​​Executor 的工作 [英] Working of Spring's ThreadPoolTaskExecutor

查看:64
本文介绍了Spring 的 ThreadPoolTask​​Executor 的工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在阅读 Spring 的 ThreadPoolTask​​Executor 的设置如何协同工作以及线程池和队列如何工作.这个 stackoverflow 答案以及 this这篇来自 Baeldung 的文章对我很有用.

据我目前所知,corePoolSize 线程数始终保持活动状态(假设 allowCoreThreadTimeOut 未设置为 true).如果所有这些线程当前都在使用中,则任何其他请求都将放入队列中.达到 queueCapacity 后,线程池大小将增加,直到达到 maxPoolSize.

直觉上,我会认为它会按如下方式工作:
corePoolSize 线程数始终保持活动状态(再次假设 allowCoreThreadTimeOut 未设置为 true).如果所有这些线程当前都在使用中并且有新请求进来,则池大小将增加,直到达到 maxPoolSize.如果还有更多请求进入,它们将被放入队列,直到达到 queueCapacity.

我想知道它以这种方式工作的原因是什么?

解决方案

您应该检查的第一个参考是文档.

直接来自 ThreadPoolExecutor(ThreadPoolTask​​Executor只是"一个包装器):

<块引用>

ThreadPoolExecutor 将根据 corePoolSize(参见 getCorePoolSize())和 maximumPoolSize(参见 getMaximumPoolSize())设置的边界自动调整池大小(参见 getPoolSize()).在方法 execute(Runnable) 中提交新任务时,如果正在运行的线程少于 corePoolSize,则会创建一个新线程来处理请求,即使其他工作线程处于空闲状态.否则,如果正在运行的线程少于 maximumPoolSize,则只有在队列已满时才会创建一个新线程来处理请求.[...]

<块引用>

如果池中当前有超过 corePoolSize 的线程,如果空闲时间超过 keepAliveTime(参见 getKeepAliveTime(TimeUnit)),多余的线程将被终止.这提供了一种在未积极使用池时减少资源消耗的方法.如果池稍后变得更加活跃,则将构建新线程.[...]

(您还没有提到 BlockingQueue 的参数,但我建议您也阅读它.这很有趣.)

为什么参数不能像您建议的那样工作?

如果在任务排队之前将池大小增加到 maximumPoolSize(如您所建议的那样),您将遇到一个问题:您将删除线程池的确定能力一名新员工值得时.

corePoolSize 是池中停留的工人数量.好处是您不必为给定的工作负载创建、终止、创建、终止、创建......新工作人员.如果您可以确定总是有多少工作,那么相应地设置 corePoolSize 是一个明智的主意.

maximumPoolSize 确定池中的最大工作线程数量.您想要控制它,因为您可以拥有多个线程池、硬件限制或只是一个不需要那么多工作线程的特定程序.

现在为什么工作队列会先被填满?因为队列容量是何时工作量如此之高的指标,所以值得创建新的工作人员.只要队列未满,核心工作人员就应该足以处理给定的工作.如果达到容量,则会创建新的工作人员来处理进一步的工作.

通过这种机制,线程池在需要时动态创建工作线程,并且只保留通常需要的数量的工作线程.这就是线程池的意义所在.

I have been reading up on how the settings of Spring's ThreadPoolTaskExecutor work together and how the thread pool and queue work. This stackoverflow answer as well as this and this article from Baeldung have been useful to me.

As far as I understand thus far, corePoolSize number of threads are kept alive at all time (assuming allowCoreThreadTimeOut is not set to true). If all of these threads are currently in use, any additional requests will be put on the queue. Once queueCapacity is reached, the thread pool size will be increased until maxPoolSize is reached.

Intuitively, I would have thought it would instead work as follows:
corePoolSize number of threads are kept alive at all time (again assuming allowCoreThreadTimeOut is not set to true). If all of these threads are currently in use and new requests come in, the pool size will be increased until maxPoolSize is reached. If there are then still more requests coming in, they will be put on the queue until queueCapacity is reached.

I wonder what would be the reasoning behind it working the way it is?

解决方案

The first reference you should check is the documentation.

Right from the documentation for ThreadPoolExecutor (ThreadPoolTaskExecutor is "just" a wrapper):

A ThreadPoolExecutor will automatically adjust the pool size (see getPoolSize()) according to the bounds set by corePoolSize (see getCorePoolSize()) and maximumPoolSize (see getMaximumPoolSize()). When a new task is submitted in method execute(Runnable), if fewer than corePoolSize threads are running, a new thread is created to handle the request, even if other worker threads are idle. Else if fewer than maximumPoolSize threads are running, a new thread will be created to handle the request only if the queue is full. [...]

If the pool currently has more than corePoolSize threads, excess threads will be terminated if they have been idle for more than the keepAliveTime (see getKeepAliveTime(TimeUnit)). This provides a means of reducing resource consumption when the pool is not being actively used. If the pool becomes more active later, new threads will be constructed. [...]

(You haven't mentioned the parameter for the BlockingQueue but I suggest you to read about it as well. It's very interesting.)

Why do the parameters not work like you've suggested they should?

If the pool size would be increased up to maximumPoolSize before tasks are queued (like you've proposed), you'd have one problem: You'd have removed the thread pool's ability to determine when a new worker is worth it.

The corePoolSize is the amount of workers that stay in the pool. The benefit is that you don't have to create, terminate, create, terminate, create ... new workers for a given workload. If you can determine how much work there will always be, it's a smart idea to set the corePoolSize accordingly.

The maximumPoolSize determines the maximum amount of workers in the pool. You want to have control over that as you could have multiple thread pools, hardware restrictions or just a specific program where you don't need as many workers.

Now why does the work queue get filled up first? Because the queue capacity is an indicator for when the amount of work is so high, that it's worth it to create new workers. As long the queue is not full, the core workers are supposed to be enough to handle the given work. If the capacity is reached, then new workers are created to handle further work.

With this mechanism the thread pool dynamically creates workers when there is a need for them and only keeps so many workers as there is usually need for. This is the point of a thread pool.

这篇关于Spring 的 ThreadPoolTask​​Executor 的工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆