背景
spring中经常使用
ThreadPoolTaskExecutor
来调用JDK的ThreadPoolExecutor初始化线程池, 尤其在有异步执行的任务时, 由于spring 异步任务默认使用的executor
不会reuse线程
, 因此需要设置默认线程池, 来
替换
spring 默认的
SimpleAsyncTaskExecutor
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xLLSstjB-1668741434112)(https://secure2.wostatic.cn/static/64FvJBaYKqNgPfUawt1QYE/image.png?auth_key=1668737566-csH8L4r5WcijBnru5MMQFB-0-de7138e88c12eeda47e1e385ffb4bdd7)]](https://img-blog.csdnimg.cn/6674dcb778bc414bb1c532f57a19f77c.png)
参数
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
写在最后
但是
软件工程实践没有银弹
, 一切都要结合实际场景去考虑
版权归原作者 勤勤啃啃 所有, 如有侵权,请联系我们删除。