前言
大家好,我是努力更文的小白,我们知道不论是面试还是工作当中,都会接触到线程池,线程池更是面试官爱问的知识点,今天我带着大家来看一看线程池的源码,虽然看源码是一件十分枯燥无味的事情,但是你不卷,总有人卷,谁也不甘心被优化!!!跟着我,卷起来!!!
继承体系
线程池的继承体系如下图所示
线程池状态
线程池状态转换如下图所示
-
首先创建出线程池,并且没有调用
shutdown
方法之前,线程池就处于正常的运行状态,即RUNNING
。处于RUNNING
状态的线程池,你提交的任务(调用submit
或者execute
方法)才会被线程池执行,处于RUNNING
状态的线程池能接受新提交的任务,并且也能处理阻塞队列中的任务。 -
处于
RUNNING
状态的线程池调用shutdown
方法之后,线程池的状态就会变成SHUTDOWN
,此时你再提交新的任务(调用submit
或者execute
方法)就会被线程池拒绝掉。但是SHUTDOWN
状态的线程池有一个特殊的点:它不是会将所有的线程立马退出,而是将之前任务队列中的任务都执行完之后线程才会依次退出。 -
处于
STOP
状态的线程池不能接受新提交的任务,也不能处理阻塞队列中的任务,会中断正在处理任务的线程。当线程池处于RUNNING
或者SHUTDOWN
状态时,调用shutdownNow
方法就会线程池就会进入该状态。 -
当所有的任务都终止了,线程池中的线程数
workCount
为0
时,线程池就会进入TIDYING
状态 -
最后一个退出的线程(即执行完任务队列中的最后一个任务后),最后一个退出的线程会把线程池的状态变成
TIDYING
,然后调用terminated
方法,线程池就会变成TERMINATED
状态了。
拒绝策略
四种拒绝策略如下:
AbortPolicy
:抛出一个异常,默认的(比较常用)CallerRunsPolicy
:交给线程池调用所在的线程进行处理DiscardPolicy
:直接丢弃任务DiscardOldestPolicy
:丢弃队列里最老的任务,将当前这个任务继续提交给线程池
属性
//高3位:表示当前线程池运行状态 除去高3位之后的低位(29位):表示当前线程池中所拥有的线程数量
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
//表示在ctl中,低COUNT_BITS位 是用于存放当前线程数量的位。COUNT_BITS的值为29
private static final int COUNT_BITS = Integer.SIZE - 3;
//低COUNT_BITS位 所能表达的最大数值。 000 11111111111111111111 => 5亿多。
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
// runState is stored in the high-order bits
//-1就是32个1来表示的,左移29位,后面补零,即只剩下三个1和29个0
//111 000000000000000000 转换成整数,其实是一个负数
private static final int RUNNING = -1 << COUNT_BITS;
//000 000000000000000000
private static final int SHUTDOWN = 0 << COUNT_BITS;
//001 000000000000000000
private static final int STOP = 1 << COUNT_BITS;
//010 000000000000000000
private static final int TIDYING = 2 << COUNT_BITS;
//011 000000000000000000
private static final int TERMINATED = 3 << COUNT_BITS;
//任务队列,当线程池中的线程达到核心线程数量时,再提交任务 就会直接提交到 workQueue
//workQueue instanceOf ArrayBrokingQueue LinkedBrokingQueue 同步队列
private final BlockingQueue<Runnable> workQueue;
//线程池全局锁,增加worker(线程) 减少 worker(线程) 时需要持有mainLock , 修改线程池运行状态时,也需要。
private final ReentrantLock mainLock = new ReentrantLock();
/**
* Set containing all worker threads in pool. Accessed only when
* holding mainLock.
*/
//线程池中真正存放 worker->thread 的地方。
private final HashSet<Worker> workers = new HashSet<Worker>();
/**
* Wait condition to support awaitTermination
*/
//当外部线程调用 awaitTermination() 方法时,外部线程会等待当前线程池状态为 Termination 为止。
//等待是如何实现的? 就是将外部线程 封装成 waitNode 放入到 Condition 队列中了, waitNode.Thread 就是外部线程,会被park掉(处于WAITING状态)。
//当线程池 状态 变为 Termination时,会去唤醒这些线程。通过 termination.signalAll() ,唤醒之后这些线程会进入到 阻塞队列,然后头结点会去抢占mainLock。
//抢占到的线程,会继续执行awaitTermination() 后面程序。这些线程最后,都会正常执行。
//简单理解:termination.await() 会将线程阻塞在这。
// termination.signalAll() 会将阻塞在这的线程依次唤醒
private final Condition termination = mainLock.newCondition();
/**
* Tracks largest attained pool size. Accessed only under
* mainLock.
*/
//记录线程池生命周期内 线程数最大值
private int largestPoolSize;
/**
* Counter for completed tasks. Updated only on termination of
* worker threads. Accessed only under mainLock.
*/
//记录线程池所完成任务总数 ,当worker(线程)退出时会将 worker完成的任务累积到completedTaskCount
private long completedTaskCount;
//创建线程时会使用 线程工厂,当我们使用 Executors.newFix... newCache... 创建线程池时,使用的是 DefaultThreadFactory
//一般不建议使用Default线程池,推荐自己实现ThreadFactory
private volatile ThreadFactory threadFactory;
/**
* Handler called when saturated or shutdown in execute.
*/
//拒绝策略,juc包提供了4中方式,默认采用 Abort..抛出异常的方式。
private volatile RejectedExecutionHandler handler;
//空闲线程存活时间,当allowCoreThreadTimeOut == false 时,会维护核心线程数量内的线程存活,超出核心线程数量的部分会被回收。
//allowCoreThreadTimeOut == true 核心数量内的线程 空闲时 也会被回收。
private volatile long keepAliveTime;
/**
* If false (default), core threads stay alive even when idle.
* If true, core threads use keepAliveTime to time out waiting
* for work.
*/
//控制核心线程数量内的线程 是否可以被回收。true 可以,false不可以。
private volatile boolean allowCoreThreadTimeOut;
/**
* Core pool size is the minimum number of workers to keep alive
* (and not allow to time out etc) unless allowCoreThreadTimeOut
* is set, in which case the minimum is zero.
*/
//核心线程数量限制。
private volatile int corePoolSize;
/**
* Maximum pool size. Note that the actual maximum is internally
* bounded by CAPACITY.
*/
//线程池最大线程数量限制。
private volatile int maximumPoolSize;
/**
* The default rejected execution handler
*/
//缺省拒绝策略,采用的是AbortPolicy 抛出异常的方式。
private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();
复制代码
-
ctl
:高3位
:表示当前线程池运行状态(runState
),除去高3位之后的低位(29位
):表示当前线程池中所拥有的线程数量(workerCount
)。 -
COUNT_BITS
:值为29
(Integer.SIZE - 3
=32 - 3 = 29
),表示在ctl
中,低COUNT_BITS位
是用于存放当前线程数量的位。 -
CAPACITY
:低COUNT_BITS位
所能表达的最大数值。000 11111111111111111111
=> 5亿多。 -
RUNNING
:表示线程池处于正常运行状态,-1
就是32
个1
来表示的,左移29
位,后面补零,即-1 << COUNT_BITS
只剩下三个1
和29
个0
,即111 000000000000000000
,转换成整数,其实是一个负数。 -
SHUTDOWN
:表示线程池处于SHUTDOWN
状态,同理0 << COUNT_BITS
,即000000000000000000....
,即就是0
-
STOP
:表示线程池处于STOP
状态,同理1 << COUNT_BITS
,即001 000000000000000000....
. -
TIDYING
:表示线程池处于TIDYING
状态,同理2 << COUNT_BITS
,即010 000000000000000000....
. -
TERMINATED
:表示线程池处于TERMINATED
状态,同理3 << COUNT_BITS
,即011000000000000000000....
. -
workQueue
:任务队列,当线程池中的线程达到核心线程数量时,再提交任务 就会直接提交到workQueue
,任务队列的实现有ArrayBrokingQueue
、LinkedBrokingQueue
等等。 -
mainLock
:线程池全局锁,增加worker
(线程) 减少worker
(线程) 时需要持有mainLock
, 修改线程池运行状态时,也需要。 -
workers
:线程池中会把线程都封装成worker
,workers
真正存放所有的worker
,即存放所有的线程。 -
largestPoolSize
:记录线程池生命周期内 线程数最大值。 -
completedTaskCount
:记录线程池所完成任务总数 ,当worker(线程)
退出时会将worker
完成的任务累积到completedTaskCount
-
threadFactory
:创建线程时会使用 线程工厂,一般不建议使用默认的,推荐自己实现ThreadFactory
-
handler
:拒绝策略,juc包提供了4中方式。AbortPolicy
:抛出一个异常,默认的(比较常用)CallerRunsPolicy
:交给线程池调用所在的线程进行处理DiscardPolicy
:直接丢弃任务DiscardOldestPolicy
:丢弃队列里最老的任务,将当前这个任务继续提交给线程池
-
keepAliveTime
:空闲线程存活时间,当allowCoreThreadTimeOut == false
时,会维护核心线程数量内的线程存活,超出核心线程数量的部分会被回收;allowCoreThreadTimeOut == true
核心数量内的线程 空闲时 也会被回收。 -
allowCoreThreadTimeOut
:控制核心线程数量内的线程 是否可以被回收。true 可以,false不可以。 -
corePoolSize
:核心线程数量限制 -
maximumPoolSize
:线程池最大线程数量限制。 -
defaultHandler
:默认的拒绝策略,采用的是AbortPolicy
抛出异常的方式。
小方法
常用的小方法源码如下:
// Packing and unpacking ctl
//获取当前线程池运行状态,即获取ctl的高三位的值+29个0
// 将ctl的值 & ~CAPACITY CAPACITY为高三位为0,低29位为1,即000 11111111111111111111
//~000 11111111111111111111 => 111 000000000000000000000
//c == ctl = 111 000000000000000000111
//111 000000000000000000111
//111 000000000000000000000
//111 000000000000000000000
private static int runStateOf(int c) { return c & ~CAPACITY; }
//获取当前线程池线程数量
//c == ctl = 111 000000000000000000111
//111 000000000000000000111
//000 111111111111111111111
//000 000000000000000000111 => 7
private static int workerCountOf(int c) { return c & CAPACITY; }
//用在重置当前线程池ctl值时 会用到
//rs 表示线程池状态 wc 表示当前线程池中worker(线程)数量
//rs:111 000000000000000000
// |
//wc:000 000000000000000111
//=
//111 000000000000000111
private static int ctlOf(int rs, int wc) { return rs | wc; }
/*
* Bit field accessors that don't require unpacking ctl.
* These depend on the bit layout and on workerCount being never negative.
*/
//比较当前线程池ctl所表示的状态,是否小于某个状态s
//c = 111 000000000000000111 < 000 000000000000000000 == true
//所有情况下,RUNNING < SHUTDOWN < STOP < TIDYING < TERMINATED
private static boolean runStateLessThan(int c, int s) {
return c < s;
}
//比较当前线程池ctl所表示的状态,是否大于等于某个状态s
private static boolean runStateAtLeast(int c, int s) {
return c >= s;
}
//小于SHUTDOWN 的一定是RUNNING。 SHUTDOWN == 0
private static boolean isRunning(int c) {
return c < SHUTDOWN;
}
//使用CAS方式 让ctl值+1 ,成功返回true, 失败返回false
//将ctl的低29位即线程数量+1
private boolean compareAndIncrementWorkerCount(int expect) {
return ctl