背景
spring中经常使用
ThreadPoolTaskExecutor
来调用JDK的ThreadPoolExecutor初始化线程池, 尤其在有异步执行的任务时, 由于spring 异步任务默认使用的executor
不会reuse线程
, 因此需要设置默认线程池, 来
替换
spring 默认的
SimpleAsyncTaskExecutor
参数
ThreadPoolTaskExecutor 不同的参数设置会使executor采用不同的策略
- CorePoolSize 核心线程数
默认值为1
, 默认不会空闲销毁的线程, 可以设置AllowCoreThreadTimeOut=true(默认为false)
来控制
核心线程空闲回收
- MaxPoolSize 最大线程数线程池能容纳的
最大
线程数 - QueueCapacity 线程池队列容量只有当队列容量满了, 才会创建新的线程执行任务, 否则放在队列中等待, 并且
等待核心线程处理任务
- RejectedExecutionHandler 当线程池达到max size时, 执行的策略如果线程池满了, 再进来新的任务, 将会执行rejected策略
改变上述参数值, 线程池分别表现为以下策略:
if 「线程池中线程的数量」
<
「corePoolSize 」:
创建新的线程来处理任务, 即便线程池中其他线程都是空闲状态
else if 「线程池中线程的数量」
==
「corePoolSize 」
&&
「QueueCapacity」未满 :
任务将被放入队列中等待线程执行
else if 「线程池中线程的数量」
>
「corePoolSize 」
&&
「QueueCapacity」已满
&&
「线程池中线程的数量」
<
「MaxPoolSize」:
创建新的线程来处理任务
else if 「线程池中线程的数量」
<
「corePoolSize 」
&&
「QueueCapacity」已满
&&
「线程池中线程的数量」
==
「MaxPoolSize」:
通过制定rejectedHandler处理
综上, 线程池执行的顺序即:
- 核心线程corePoolSize?
- 任务队列workQueue?
- 最大线程 maximumPoolSize?
- 如果三者都满了,使用handler处理被拒绝的任务
另外 如果线程池中的线程数
>
「corePoolSize」, 并且超过了『keepAliveTime(默认为60s)』, 线程将被回收, 以此来达到
动态管理
线程池的线程数
如何设置这些值
因为要考虑:
- 运行机器的
硬件参数
- 期望的CPU占用率
- 不同
应用程序类型
(IO密集型/CPU密集型) - 业务场景是否特别要求性能
种种情况, 组合的case就非常多了, 推荐的设置值是:
- corePoolSize = CPU线程数/2
Runtime.getRuntime().availableProcessors()//获取逻辑核心数,如6核心12线程,那么返回的是12
- maxPoolSize = CPU 线程数
- queueCapacity = ( corePoolSize / 任务处理时间 ) * 期望等待时间(秒)
- rejectedExecutionHandler = new ThreadPoolExecutor.CallerRunsPolicy() 如果线程池满了, 丢给caller线程执行
有兴趣参考:
https://juejin.cn/post/6948034657321484318
写在最后
但是
软件工程实践没有银弹
, 一切都要结合实际场景去考虑
版权归原作者 勤勤啃啃 所有, 如有侵权,请联系我们删除。