作者:指尖上的榴莲
www.jianshu.com/p/704a6c5d337c
一.概述
线程池,顾名思义就是存放线程的池子,池子里存放了很多可以复用的线程。
如果不用类似线程池的容器,每当我们需要执行用户任务的时候都去创建新的线程,任务执行完之后线程就被回收了,这样频繁地创建和销毁线程会浪费大量的系统资源。
因此,线程池通过线程复用机制,并对线程进行统一管理,具有以下优点:
- 降低系统资源消耗。通过复用已存在的线程,降低线程创建和销毁造成的消耗;
- 提高响应速度。当有任务到达时,无需等待新线程的创建便能立即执行;
- 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗大量系统资源,还会降低系统的稳定性,使用线程池可以进行对线程进行统一的分配、调优和监控。
ThreadPoolExecutor是线程池框架的一个核心类,本文通过对threadPoolExecutor源码的分析(基于JDK 1.8),来深入分析线程池的实现原理。
二.ThreadPoolExecutor类的属性
先从ThreadPoolExecutor类中的字段开始:
在ThreadPoolExecutor类的这些属性中,线程池状态是控制线程池生命周期至关重要的属性,这里就以线程池状态为出发点进行研究。
通过上面的源码可知,线程池的运行状态总共有5种,其值和含义分别如下:
- RUNNING: 高3位为111,接受新任务并处理阻塞队列中的任务
- SHUTDOWN: 高3位为000,不接受新任务但会处理阻塞队列中的任务
- STOP:高3位为001,不会接受新任务,也不会处理阻塞队列中的任务,并且中断正在运行的任务
- TIDYING: 高3位为010,所有任务都已终止,工作线程数量为0,线程池将转化到TIDYING状态,即将要执行terminated()钩子方法
- TERMINATED: 高3位为011,terminated()方法已经执行结束
然而,线程池中并没有使用单独的变量来表示线程池的运行状态,而是使用一个AtomicInteger类型的变量ctl来表示线程池的控制状态,其将线程池运行状态与工作线程的数量打包在一个整型中,用高3位来表示线程池的运行状态,低29位来表示线程池中工作线程的数量,对ctl的操作主要参考以下几个函数:
接下来,我们看一下线程池状态的所有转换情况,如下:
- RUNNING -> SHUTDOWN:调用shutdown(),可能在finalize()中隐式调用
- (RUNNING or SHUTDOWN) -> STOP:调用shutdownNow()
- SHUTDOWN -> TIDYING:当缓存队列和线程池都为空时
- STOP -> TIDYING:当线程池为空时
- TIDYING -> TERMINATED:当terminated()方法执行结束时
通常情况下,线程池有如下两种状态转换流程:
- RUNNING -> SHUTDOWN -> TIDYING -> TERMINATED
- RUNNING -> STOP -> TIDYING -> TERMINATED
三.ThreadPoolExecutor类的构造方法
通常情况下,我们使用线程池的方式就是new一个ThreadPoolExecutor对象来生成一个线程池。接下来,先看ThreadPoolExecutor类的构造函数:
接下来,看下最后一个构造函数的具体实现: