线程池
线程池原理知识
1. 线程池基础
线程池是什么
线程池概念:
- 是⼀种基于
池化思想
管理线程的工具。
线程池好处:
- 如果没有线程池,线程过多会带来额外的开销,例如:
创建销毁线程
的开销、调度线程
的开销 - 线程池负责维护多个线程,一方面避免了处理任务时创建销毁线程开销的代价,另一方面避免了线程数量膨胀导致的过分调度问题。
- 线程池好处包括:
- 降低资源消耗:通过池化技术重复利用已创建的线程,降低线程创建和销毁造成的损耗。
- 提高响应速度:任务到达时,无需等待线程创建即可立即执行。
- 提高线程的可管理性: 线程是稀缺资源,如果无限制创建,不仅会消耗系统资源,还会因为线程的不合理分布导致资源调度失衡,降低系统的稳定性。使用线程池可以进行统一的分配、监控。
线程池解决了什么问题
线程池解决的核心问题就是资源管理问题
。在并发环境下,系统不能够确定在任意时刻,有多少任务需要执行,有多少资源需要投入。这种不确定性会降低系统的稳定性。
为了解决资源分配问题,线程池采用了池化
的思想。就是将资源统一在一起管理的思想。
2. 线程池核心设计与实现
总体设计
ThreadPoolExecutor一方面维护自身的生命周期
,另一方面管理线程和任务
,使两者良好的结合从而执行并行任务。
生命周期管理
ThreadPoolExecutor的运行状态有5种
,分别为
任务执行机制
1. 任务调度
任务调度是线程池的主要入口,当用户提交了⼀个任务,接下来这个任务将如何执行都是由这个阶段决定的。
任务调度的执行过程:
- 首先检测线程池运行状态,如果不是RUNNING,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。
- 如果workerCount < corePoolSize,则创建并启动⼀个线程来执行新提交的任务。
- 如果workerCount >= corePoolSize,且线程池内的阻塞队列未满,则将任务添加到该阻塞队列中。
- 如果workerCount >= corePoolSize && workerCount < maximumPoolSize,且线程池内的阻塞队列已满,则创建并启动⼀个线程来执行新提交的任务。
- 如果workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满,则根据拒绝策略来处理该任务,默认的处理方式是直接抛异常。
2. 任务缓冲
线程池中是以生产者消费者模式,通过一个阻塞队列来实现的。阻塞队列缓存任务,工作线程从阻塞队列中获取任务。
3. 任务申请
任务申请有2种:
- 任务直接由新创建的线程执行,无需调用 getTask() 获取任务。
- 任务先被放到任务队列,然后再由空闲线程申请,此时线程需要调用 getTask() 申请任务。
getTask() 申请任务流程图
4. 任务拒绝
当线程池的任务缓存队列已满,并且线程池中的线程数目达到 maximumPoolSize
时,就需要拒绝掉该任务,采取任务拒绝策略,保护线程池。
拒绝策略是⼀个接口,其设计如下:
public interface RejectedExecutionHandler {
void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}
⽤户可以通过实现这个接口去定制拒绝策略,也可以选择JDK提供的四种已有拒绝策略,其特点如下:
Worker线程管理
Worker线程
Worker线程增加
Worker线程回收
Worker线程执行任务
3. 线程池在业务中的实践
业务背景
场景一:快速响应用户请求
用户的发起的实时请求,往往需要多个调用,之后要将所有的数据聚合起来返回给用户。
为了追求响应时间,可以使用线程池将调用封装成任务并行的执行,缩短总体响应时间。
场景二:快速处理批量任务
这种场景需要执行大量的任务,并不要求瞬时完成,而是关注在单位时间内,尽可能的处理更多的任务。
可以使用线程池,并行执行任务,提高吞吐量。
实际问题及方案思考
4. 动态化线程池设计方案
动态化线程池:
- 将线程池的参数从代码中迁移到分布式配置中心上,实现线程池参数可动态配置和即时生效,线程池参数动态化前后的参数修改流程对比如下:
动态化线程池整体设计:
动态修改配置
线程池构造参数有8个,但是最核心的是3个:corePoolSize
、maximumPoolSize
,workQueue
所以线程池只需要提供这三个关键参数的配置即可。
线程池信息监控
动态化线程池考虑了多个维度的监控。如:线程池活跃度、任务的执行Transaction(频率、耗时)、Reject异常、线程池内部统计信息等。
这些监控信息既能从多个维度分析线程池的使用情况,又能在出现问题第一时间通知到用户,从而避免故障或加速故障恢复。
线程池告警通知
可以从两方面来看线程池的过载判定条件。
- 发生了 Reject 异常
- 任务队列中的等待任务超过指定的阈值、
以上两种情况发生了都会触发告警,告警信息会通过邮件发送给负责人。
参考文章:
标签:一篇,队列,Worker,就够,任务,线程,执行,动态化 From: https://blog.csdn.net/weixin_44147535/article/details/135191215