一、基本概念
1.1解决的问题
线程池本质解决的问题是线程生命周期开销和资源不足问题,在大流量和高并发情况下,系统不确定在任意时刻有多少线程需要执行,需要多少资源需要投入,不合理的使用和管理,会带来以下若干问题:
- 无限创建线程,导致系统资源耗尽;
- 频繁的创建、销毁线程对cpu系统的消耗更大,系统性能降低;
- 系统稳定性无法保障低,因为无法管理线程资源分布;
1.2如何解决
线程池采用“池化(Pooling)”思想,将线程资源统一在一起管理,通过构建一个生产者消费者模型,将实际执行的线程和提交的任务解耦,从而良好地缓冲任务和复用线程。每当有任务时先从线程池里获取有效线程,如果没有则放置队列中,当达到一定线程数时采取一定拒绝策略返回,直至线程池资源耗尽;
1.3好处
- 降低线程资源消耗:复用已创建线程,降低线程创建和销毁带来的消耗;
- 提高响应速度:任务无需创建线程,立刻执行;
- 提高线程可管理性:统一管理、调优和监控;
- 提供其他扩展功能:允许扩展定时执行任务功能ScheduledThreadPoolExecutor等;
二、基本原理
Java中的线程池核心实现类为ThreadPollExcutor,UML类图如下:
Executor:顶层接口,定义execute接口,提供任务提交和任务执行解耦思想;
ExecutorService:集成Executor接口,扩充了任务能力,为一个或者一批异步任务生成future方法,提供停止线程池的接口;
AbstractExecutorService:实现以上接口,抽象执行任务流程;
ThreadPoolExecutor:主要维护自身生命周期状态、管理线程与任务,管理运行机制如下:
线程池在内部实际上构建了一个生产者消费者模型,将线程和任务两者解耦,并不直接关联,从而良好的缓冲任务,复用线程。线程池的运行主要分成两部分:任务管理、线程管理。任务管理部分充当生产者的角色,当任务提交后,线程池会判断该任务后续的流转:(1)直接申请线程执行该任务;(2)缓冲到队列中等待线程执行;(3)拒绝该任务。线程管理部分是消费者,它们被统一维护在线程池内,根据任务请求进行线程的分配,当线程执行完任务后则会继续获取新的任务去执行,最终当线程获取不到任务的时候,线程就会被回收。
2.1生命周期管理
线程池内部使用一个原子类AtomicInteger维护两个变量值:高3位保存运行状态runState(5种),低29位保存线程数量workerCount;因为在任务执行判断时要同时判断状态和线程数,保持两个数据一致性;示意图如下:
具体源码如下:
|