关于线上常用的几种线程池配置
2021/9/8 23:07:28
本文主要是介绍关于线上常用的几种线程池配置,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
线程池可以帮助我们省去创建、回收线程所带来的资源消耗,这也是目前使用线程池的主要原因:
下面我根据线上业务依次分析常见的几种线程池并给出个人理解:
- SingleThreadPool:无界队列,核心线程、最大线程都为 1
特点:只有一个线程,阻塞队列使用 LinkedBlockingQueue,链表无界。优点在于保证顺序
我个人不推荐使用这种线程池,首先它的应用场景很少,单个线程也无法发挥多核的优势。只适合用于一些边缘业务,不重要也不考虑稳定性的场景可以通过这个线程池慢慢跑
如果只是为了保证顺序,我更倾向通过消息队列这种方式,而不是线程池。首先通过消息队列的好处在于流量可控,这点非常重要,哪怕只通过一个线程每次消费一条消息,消息挤压在 MQ 都比挤压在无界队列好。一般线上强烈不建议使用无界队列,一旦涉及到上线,重启你完全无法预知阻塞队列中还有多少未执行的任务,一旦重启丢了就是丢了,完全不能找回
重要的事情再说一遍,线上强烈不建议使用无界队列作为线程池的阻塞队列,因为无法预知消息的积压量,而且很有可能造成内存泄漏
- newFixedThreadPool:无界队列,核心线程、最大线程都为 n
和 SingleThreadPool 类似,唯一区别在于可以多线程并发。因为使用无界队列,还是不建议使用
- newCachedThreadPool:没有核心线程,工作线程无界
这种线程池主要用于应对流量不均匀的场景,对于存在业务高峰期的系统可以尝试使用,不过需要防止高并发流量一下次创建太多线程,虽然可能系统本身没有挂,但是多线程并发的流量一下子把其它中间件打挂了,比如 MySQL
- ScheduledThreadPool:有核心线程,最大线程无界,阻塞队列有界,存在优先级维度
之前博客中提到可以做优先级,主要用于定时任务之类。目前我线上用到较少,不过应该可以考虑使用,这里优先级是通过阻塞队列实现,可以将一些重要的任务交给该线程池执行。至于定时器,线上很少会通过线程池做定时,一般公司会有专业的定时任务中间件,如 XXLJOB 等等
- SingleThreadScheduledPool:和上一种类似,唯一区别在于单线程
单线程的线程池线上用的较少,因为效率还是比较低的,无法发挥多核的优势,不如 ScheduledThreadPool
常见的五种线程池介绍完了,其实一般线上更推荐大家自己写参数,而不是套模板,根据自己业务量配置出的线程池肯定比这种统一出来的线程池好使,而且更契合实际业务,不过有几点共识可以遵守:
- 尽量不要用单线程线程池,无法发挥多核优势
- 尽量不要使用无界队列,消息可以积压在 kafka 不要积压在无界队列
- 核心线程数、最大线程数最好根据业务自行设置
- 建议不要只用某一种线程池,多定义几种不同类型的线程池,写在同一个 Service 中,通过 Spring IOC 容器管理对外提供不同服务:
最后我再简单介绍目前我的应用常用的几种线程池配置:
- 普通线程池,核心线程数 10、最大线程数 20,阻塞队列有界
- 守护线程池,配置同普通线程
- 无队列线程池,核心线程数20、最大线程数 40,阻塞队列长度 0
守护线程池:主要执行一些清理及不关键的业务场景
普通线程池:绝大多数业务场景都可以使用普通线程池
无队列线程池:主要用于处理一些对性能有要求的场景,比如消费 MQ
至于拒绝策略,守护线程池可以设置为 DiscardPolicy,因为其中它的工作不重要,适当可以丢弃。普通线程池和无队列线程池都采用CallerRunsPolicy,线上的 MQ 无论如何都不能丢弃。只能通过当前线程执行,这样的结果可能导致 mq 消费过慢,此时可以通过扩容或者优化逻辑的方式防止 mq 积压
这篇关于关于线上常用的几种线程池配置的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-02Java管理系统项目实战入门教程
- 2024-11-02Java监控系统项目实战教程
- 2024-11-02Java就业项目项目实战:从入门到初级工程师的必备技能
- 2024-11-02Java全端项目实战入门教程
- 2024-11-02Java全栈项目实战:从入门到初级应用
- 2024-11-02Java日志系统项目实战:初学者完全指南
- 2024-11-02Java微服务系统项目实战入门教程
- 2024-11-02Java微服务项目实战:新手入门指南
- 2024-11-02Java项目实战:新手入门教程
- 2024-11-02Java小程序项目实战:从入门到简单应用