线程池的介绍
- 为什么要用线程池?
系统中频繁的创建线程、关闭线程是相当消耗资源的,会降低机器的整体性能。线程池维护多个线程,等待监督管理者分配可并发执行的任务。这种做法,一方面避免了处理任务时创建销毁线程开销的代价,另一方面避免了线程数量膨胀导致的过分调度问题,保证了对内核的充分利用。
使用线程池可以带来一系列好处:降低资源消耗、提高响应速度、提高线程的可管理性等。
- 创建线程池
创建线程池推荐使用ThreadPoolExecutor。阿里巴巴开发规范也强制使用ThreadPoolExecutor来创建线程池。

手动创建线程池的构造函数如下:
public ThreadPoolExecutor(int corePoolSize, //核心线程数量
int maximumPoolSize, //最大线程数
long keepAliveTime, //超时了多久没人调用就释放
TimeUnit unit, //超时时间单位
BlockingQueue<Runnable> workQueue,//阻塞队列
ThreadFactory threadFactory, //线程工厂 创建线程的一般不用动
RejectedExecutionHandler handler //拒绝策略
)
- 线程池的内部运行原理
线程池在内部实际上构建了一个生产者消费者模型,将线程和任务两者解耦,并不直接关联,从而良好的缓冲任务,复用线程。线程池的运行主要分成两部分:任务管理、线程管理。任务管理部分充当生产者的角色,当任务提交后,线程池会判断该任务后续的流转:(1)直接申请线程执行该任务;(2)缓冲到队列中等待线程执行;(3)拒绝该任务。线程管理部分是消费者,它们被统一维护在线程池内,根据任务请求进行线程的分配,当线程执行完任务后则会继续获取新的任务去执行,最终当线程获取不到任务的时候,线程就会被回收。

- 线程池的生命周期
查看代码
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3; //==29
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
//yds: 高三位记录线程池生命状态,低29位记录当前工作线程数
// runState is stored in the high-order bits
// 二进制 负数 用正数的补码表示
// 1 = 0000 0000 0000 0000 0000 0000 0000 0001
// 1111 1111 1111 1111 1111 1111 1111 1110 反码(取反)
// -1 = 1111 1111 1111 1111 1111 1111 1111 1111 补码(反码+1)
// -1 左移29位 1110 0000 0000 0000 0000 0000 0000 0000
private static final int RUNNING = -1 << COUNT_BITS; //高三位:111
private static final int SHUTDOWN = 0 << COUNT_BITS; //高三位:000
private static final int STOP = 1 << COUNT_BITS; //高三位:001
private static final int TIDYING = 2 << COUNT_BITS; //高三位:010
private static final int TERMINATED = 3 << COUNT_BITS; //高三位:011
// Packing and unpacking ctl
private static int runStateOf(int c) {
return c & ~CAPACITY;
} //计算当前的运行状态
private static int workerCountOf(int c) {
return c & CAPACITY;
} //计算当前的线程数量
private static int ctlOf(int rs, int wc) { //通过状态和线程数量生成ctl
return rs | wc;
}
通过阅读源码可知,线程池中用一个 AtomicInteger ctl 变量来同时维护 线程状态 和 线程数量 。ctl32位长度,高3位表示线程状态,低29位表示线程数量。两个变量之间互不干扰。用一个变量去存储两个值,可避免在做相关决策时,出现不一致的情况,不必为了维护两者的一致,而占用锁资源。
线程池的状态如下
/**
* 源码注释
* RUNNING: Accept new tasks and process queued tasks
* SHUTDOWN: Don't accept new tasks, but process queued tasks
* STOP: Don't accept new tasks, don't process queued tasks,
* and interrupt in-progress tasks
* TIDYING: All tasks have terminated, workerCount is zero,
* the thread transitioning to state TIDYING
* will run the terminated() hook method
* TERMINATED: terminated() has completed
*/
| 状态 | 解释 |
| RUNNING | 接受新任务并处理排队任务 |
| SHUTDOWN | 不接受新任务,但处理排队任务 |
| STOP | 不接受新任务,也不执行队列中的任务,会中断正在处理中的任务 |
| TIDYING | 所有任务已终止, workerCount(工作线程数)为零,转换到状态 TIDYING 的线程将运行 terminate()方法 |
| TERMINATED | terminate() 方法已完成后进入该状态 |
线程池的状态之间的转换关系如下

- 任务调度机制
首先,所有任务的调度都是由execute方法完成的,这部分完成的工作是:检查现在线程池的运行状态、运行线程数、运行策略,决定接下来执行的流程,是直接申请线程执行,或是缓冲到队列中执行,亦或是直接拒绝该任务。其执行过程如下:
- 首先检测线程池运行状态,如果不是RUNNING,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。
- 如果workerCount < corePoolSize,则创建并启动一个线程来执行新提交的任务。
- 如果workerCount >= corePoolSize,且线程池内的阻塞队列未满,则将任务添加到该阻塞队列中。
- 如果workerCount >= corePoolSize && workerCount < maximumPoolSize,且线程池内的阻塞队列已满,则创建并启动一个线程来执行新提交的任务。
- 如果workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满, 则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
查看代码
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) { //1.判断核心线程数是否已满,没满直接添加核心线程来执行任务 (当前线程数量 < 核心线程数 则 添加核心线程)
if (addWorker(command, true))
return;
c = ctl.get();//添加核心线程失败,重新获取ctl
}
if (isRunning(c) && workQueue.offer(command)) {//2.线程池运行状态 且 核心线程数量已到达最大 则 将任务添加到阻塞队列(队列未满则添加成功)
int recheck = ctl.get();//再次获取ctl,
if (!isRunning(recheck) && remove(command))//3.线程池不在运行状态,则执行拒绝策略{注意,如果线程池不在运行状态,就会删掉(remove)任务,然后在执行拒绝策略}
reject(command);
else if (workerCountOf(recheck) == 0)//4.线程池运行正常,工作线程数量==0,{注意:此时已经讲一个任务放入了队列,但是没有工作线程,要去添加非核心线程}
addWorker(null, false); //添加任务为空的工作线程,处理阻塞队列中的任务,避免队列中没人执行
} else if (!addWorker(command, false))// 线程池运行状态在运行状态,任务添加队列失败(队列满了),则 添加非核心线程来执行任务,若添加失败则执行拒绝策略
reject(command);
}
调度流程图如下:

- 阻塞队列
常用的阻塞队列有:

- 拒绝策略
拒绝策略有以下四种:

详细信息如下:
//抛出RejectedExecutionException的被拒绝任务的处理程序。
//new ThreadPoolExecutor.AbortPolicy()
//被拒绝任务的处理程序,直接在execute方法的调用线程中运行被拒绝的任务(main线程执行),除非执行程序已关闭,在这种情况下,任务将被丢弃。
//new ThreadPoolExecutor.CallerRunsPolicy()
//拒绝任务的处理程序,丢弃最旧的未处理请求,然后重试execute ,除非执行程序被关闭,在这种情况下任务被丢弃。
//new ThreadPoolExecutor.DiscardOldestPolicy()
//被拒绝任务的处理程序,它默默地丢弃被拒绝的任务。
//new ThreadPoolExecutor.DiscardOldestPolicy()
- 线程池执行任务过程
线程池执行任务调用方法如下:可对源码做一个简单分析

接着可以看看addWorker(Runnable firstTask, boolean core) 的源码逻辑
查看代码
private boolean addWorker(Runnable firstTask, boolean core) {
retry: //标记外侧循环
//以下两个循环的目的就是进过判断给工作线程标识+1
for (; ; ) {
int c = ctl.get(); //ctl 记录线程池状态和线程池工作状态的
int rs = runStateOf(c);//线程池状态
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN && // 除了RUNNING的状态
!(rs == SHUTDOWN && firstTask == null && !workQueue.isEmpty()) // (a && b && c):abc 有一个false就直接返回false
// 1.(rs == SHUTDOWN --> 如果rs不是SHUTDOWN则说明是更高的状态,STOP之类的,这时就不需要创建工作线程了)
// 2.(firstTask == null --> 创建线程处理队列中的任务) 如果任务为null,且线程池状态不是RUNNING 则不需要处理
// 3. !workQueue.isEmpty() 对列为空,加两次非操作,--> 不需要处理
//注意 SHUTDOWN 状态下的线程池是要处理队列中的任务的
) {
//创建工作线程失败
return false;
}
for (; ; ) {
int wc = workerCountOf(c); //工作线程 个数
if (wc >= CAPACITY || //工作线程大于等于 最大容量 ,无需 创建新的线程
wc >= (core ? corePoolSize : maximumPoolSize)) // 工作线程大于等于 (核心或者非核心)线程数
return false;
//将工作线程+1,采取 CAS 的方式
if (compareAndIncrementWorkerCount(c))
break retry;//成功 返回外层循环
// 失败(线程+1的时候 并发产生资源争抢、锁) 重新获取 ctl
c = ctl.get(); // Re-read ctl
//判断线程池状态与开始是否相同 若有变化结束本次外侧循环,进入下次外侧循环;若没有变化重新执行内侧循环
if (runStateOf(c) != rs)
continue retry; //结束本次外侧循环,进入下次外侧循环
// else CAS failed due to workerCount change; retry inner loop
}
}
// 到此 完成了 工作线程标识+1 的操作
boolean workerStarted = false; //worker 开始 false
boolean workerAdded = false; //worker 添加 false
Worker w = null; //工作线程
try {
//创建任务 传入任务
w = new Worker(firstTask);//Worker 实现了 Runnable
final Thread t = w.thread; //从Worker 中获取线程
if (t != null) {
final ReentrantLock mainLock = this.mainLock; // 获取线程池的全局锁,避免我在创建线程的时候,其他线程干掉了线程池
mainLock.lock();
try {
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
int rs = runStateOf(ctl.get()); //获取线程池的状态
if (rs < SHUTDOWN || //-->RUNNING
(rs == SHUTDOWN && firstTask == null)) { //--->创建线程测试阻塞队列任务
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException(); //给线程已经启动了,抛异常
workers.add(w); //将工作线程添加到集合中 HashSet<Worker> workers
int s = workers.size();
if (s > largestPoolSize)//largestPoolSize 一直追踪 当前的最大线程数
largestPoolSize = s;
workerAdded = true; //添加工作线程成功
}
} finally {
mainLock.unlock();
}
if (workerAdded) {
t.start(); //启动工作线程
workerStarted = true; //启动工作成功
}
}
} finally {
if (!workerStarted) //启动工作失败
addWorkerFailed(w);
}
return workerStarted; //返回线程是否启动成功
}
再看Worker源码
查看代码
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable {
/**
* This class will never be serialized, but we provide a
* serialVersionUID to suppress a javac warning.
*/
private static final long serialVersionUID = 6138294804551838833L;
/**
* Thread this worker is running in. Null if factory fails.
*/
final Thread thread;
/**
* Initial task to run. Possibly null.
*/
Runnable firstTask;
/**
* Per-thread task counter
*/
volatile long completedTasks;
/**
* Creates with given first task and thread from ThreadFactory.
*
* @param firstTask the first task (null if none)
*/
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this); //将worker 自己传进去。thread(Runable runable)调用start()方法的时候 --->实则调用runable.run(),
// 在Worker 对应下面的run() 方法
}
/**
* Delegates main run loop to outer runWorker
*/
//重新的run()方法
public void run() {
runWorker(this);
}
// Lock methods
//
// The value 0 represents the unlocked state.
// The value 1 represents the locked state.
protected boolean isHeldExclusively() {
return getState() != 0;
}
protected boolean tryAcquire(int unused) {
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
protected boolean tryRelease(int unused) {
setExclusiveOwnerThread(null);
setState(0);
return true;
}
public void lock() {
acquire(1);
}
public boolean tryLock() {
return tryAcquire(1);
}
public void unlock() {
release(1);
}
public boolean isLocked() {
return isHeldExclusively();
}
void interruptIfStarted() {
Thread t;
if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
}
}
}
}
再看runWork()方法源码:
查看代码
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();//获取当前线程
Runnable task = w.firstTask; //拿到任务
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
// 情况1:任务不为空--->执行任务
// 情况2:任务为空---> 通过 getTask() 从阻塞队列中获取任务
while (task != null || (task = getTask()) != null){ // 此处 用 "与" 操作,task==null(核心线程和非线程都无任务执行)的情况下才会getTask(队列获取任务)。线程池的执行优先级阻塞队列里面的最后执行
w.lock();//加锁避免任务中断
// If pool is stopping, ensure thread is interrupted;
// if not, ensure thread is not interrupted. This
// requires a recheck in second case to deal with
// shutdownNow race while clearing interrupt
if ((runStateAtLeast(ctl.get(), STOP) || //判断线程池状态是否>= STOP 即线程池 is stoping
(Thread.interrupted() && runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted()
){
wt.interrupt();
}
try {
beforeExecute(wt, task); //执行任务之前操作 开发者可重新
Throwable thrown = null;
try {
task.run();//线程执行任务
} catch (RuntimeException x) {
thrown = x; throw x;
} catch (Error x) {
thrown = x; throw x;
} catch (Throwable x) {
thrown = x; throw new Error(x);
} finally {
afterExecute(task, thrown); //执行任务之后操作 开发者可重新
}
} finally {
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly);//获取不到任务时,主动回收自己
}
}
再看getTask()源码
private Runnable getTask() {
//记录上次从队列中拉取的识货是否超时
boolean timedOut = false; // Did the last poll() time out?
for (; ; ) {
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) { // 线程池状态至少为 SHUTDOWN -->{1:此案城池至少为STOP || 2:队列为空}
decrementWorkerCount(); //工作线程-1
return null;
}
int wc = workerCountOf(c); //工作线程个数重新获取一下。 次数说明线程池人在 RUNNING 状态
// Are workers subject to culling?
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize; // 允许核心线程超时 || 工作线程>核心线程数
if ((wc > maximumPoolSize || (timed && timedOut)) //工作线程数 > 最大线程数 或 [ timed == true : (允许核心线程超时 || 工作线程>核心线程数) && timedOut == true: 上次在队列里面拉取线程超时 ]
&& (wc > 1 || workQueue.isEmpty())) { // 工作线程 > 1 或 队列为空
if (compareAndDecrementWorkerCount(c)) //利用CAS 对工作线程 -1 成功 返回 null;失败 结束本轮循环
return null;
continue;
}
try {
//time = true:poll(,,)超时等待拉取任务,keepAliveTime没有获取到有效任务,则返回null
//time = false:take()阻塞拉取任务,只到获取有效任务。
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : //poll 超时 return null
workQueue.take(); // 一般不会为空
if (r != null)
return r; // r!=null :返回队列中获取的任务
timedOut = true; // r==null : 超时,进如下一轮循环
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
再看看processWorkerExit()源码
private void processWorkerExit(Worker w, boolean completedAbruptly) {
// completedAbruptly == true : runWorker() 没有正常执行完成,出现了异常。线程数量-1
if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
decrementWorkerCount();
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
completedTaskCount += w.completedTasks; // 任务完成计数器
workers.remove(w); //从工做线程集合中移除当前 工作线程
} finally {
mainLock.unlock();
}
// 根据线程池状态进行判断是否结束线程池
tryTerminate();
int c = ctl.get();
if (runStateLessThan(c, STOP)) { //线程池状态 RUNNING,SHUTDOWN 的时候进入本方法说明了异常中断了,--> 需要判断是否-- addWorker(null, false);
if (!completedAbruptly) { //runWorker(Worker w) 执行正常
int min = allowCoreThreadTimeOut ? 0 : corePoolSize; // min : 至少需要的工作线程数
if (min == 0 && !workQueue.isEmpty()) // 假如队列有任务等待 则至少保留一个工作线程
min = 1;
if (workerCountOf(c) >= min) // 当前工作线程数满足最少需要的线程数 则不用addWor();
return; // replacement not needed
}
addWorker(null, false);
}
}
本文来自博客园,作者:iyandongsheng,转载请注明原文链接:https://www.cnblogs.com/ieas/articles/15977340.html

浙公网安备 33010602011771号