线程池
什么是线程池?
为了避免系统频繁地创建和销毁线程,我们可以让创建 的线程复用。
在线程池中,总有那么几个活跃线程,当你需要使用线程时,可以从池子中随便拿一个空闲线程,当完成工作 时,并不急着关闭线程,而是将这个线程退回到线程池中,方便其他人使用。
简而言之,在使用线程池后,创建线程变成了从线程池获得空闲线程,关闭线程变成了向线程池归还线程。
线程池的工作原理
当一个任务提交至线程池之后:
- 线程池首先当前运行的线程数量是否少于corePoolSize。如果是,则创建一个新的工作线程来执行任务。如果都在执行任务,则进入2;
- 判断BlockingQueue是否已经满了,倘若还没有满,则将线程放入BlockingQueue。否则进入3;
- 如果创建一个新的工作线程将使当前运行的线程数量超过maximumPoolSize,则交给RejectedExecutionHandler来处理任务。
当ThreadPoolExecutor创建新线程时,通过CAS来更新线程池的状态ctl。
线程池的构造函数
public ThreadPoolExecutor(int corePoolSize, // 核心线程数
int maximumPoolSize, // 最大线程数
long keepAliveTime, // 当线程数量大于核心线程数时,空闲线程最大的生存期为keepAliveTime
TimeUnit unit, // keepAliveTime的时间单位
BlockingQueue<Runnable> workQueue,// 待执行的任务队列
ThreadFactory threadFactory, // 用于创建新线程的工厂类
RejectedExecutionHandler handler) // 由于达到线程边界和队列容量而无法执行时使用的拒绝策 略实现类
-
corePoolSize:
线程池中的核心线程数,当提交一个任务时,线程池创建一个新线程执行任务,直到当前线程数等于corePoolSize, 即使有其他空闲线程能够执行新来的任务, 也会继续创建线程;如果当前线程数为corePoolSize,继续提交的任务被保存到阻塞队列中,等待被执行;如果执行了线程池的prestartAllCoreThreads()方法,线程池会提前创建并启动所有核心线程。 -
workQueue:
用来保存等待被执行的任务的阻塞队列。 -
maximumPoolSize:
线程池中允许的最大线程数。如果当前阻塞队列满了,且继续提交任务,则创建新的线程执行任务,前提是当前线程数小于maximumPoolSize;当阻塞队列是无界队列, 则maximumPoolSize则不起作用, 因为无法提交至核心线程池的线程会一直持续地放入workQueue。 -
keepAliveTime:
线程空闲时的存活时间,即当线程没有任务执行时,该线程继续存活的时间;默认情况下,该参数只在线程数大于corePoolSize时才有用, 超过这个时间的空闲线程将被终止。 -
unit:
keepAliveTime的单位。 -
threadFactory:
创建线程的工厂,通过自定义的线程工厂可以给每个新建的线程设置一个具有识别度的线程名。默认为DefaultThreadFactory。 -
handler:
线程池的拒绝策略,当阻塞队列满了,且没有空闲的工作线程,如果继续提交任务,必须采取一种策略处理该任务。
RejectedExecutionHandler 拒绝策略
- AbortPolicy
丢弃任务并抛出RejectedExecutionException异常,默认策略。 - DiscardPolicy
丢弃任务,但是不抛出异常。 - DiscardOldestPolicy
丢弃队列中最前⾯的任务,然后重新尝试执⾏任务。 - CallerRunsPolicy
由调⽤线程处理该任务。
BlockingQueue 任务队列
- ArrayBlockingQueue
它是⼀个有界的阻塞队列,其内部实现是将对象放到⼀个数组⾥。⼀但初始化,⼤⼩就⽆法修改。(基于数组结构的有界阻塞队列,按FIFO排序任务) - LinkedBlockingQueue
它内部以⼀个链式结构(链接节点)对其元素进⾏存储。可以指定元素上限,否则,上限则为Integer.MAX_VALUE。(基于链表结构的阻塞队列,按FIFO排序任务,吞吐量通常要高于ArrayBlockingQuene) - DelayQueue
它对元素进⾏持有直到⼀个特定的延迟到期。注意:进⼊其中的元素必须实现Delayed接⼝。 - SynchronousQueue
它是⼀个特殊的队列,它的内部同时只能够容纳单个元素。如果该队列已有⼀个元素的话,那么试图向队列中插⼊⼀个新元素的线程将会阻塞,直到另⼀个新线程将该元素从队列中抽⾛。同样的,如果队列为空,试图向队列中抽取⼀个元素的线程将会被阻塞,直到另⼀个线程向队列中插⼊了⼀条新的元素。因此,它其实不太像是⼀个队列,⽽更像是⼀个汇合点。(一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQuene) - PriorityBlockingQueue
它是⼀个⽆界的并发队列。⽆法向这个队列中插⼊null值。所有插⼊到这个队列中的元素必须实现Comparable接⼝。因此该队列中元素的排序就取决于你⾃⼰的Comparable实现。(具有优先级的无界阻塞队列)
Executors中提供的线程池的实现
Executors提供四种线程池:
-
newCachedThreadPool
创建⼀个可缓存线程池,如果线程池⻓度超过处理需要,可灵活回收空闲线程,若⽆可回收,则新建线程。- 主线程调用SynchronousQueue的offer()方法放入task, 倘若此时线程池中有空闲的线程尝试读取 SynchronousQueue的task, 即调用了SynchronousQueue的poll(), 那么主线程将该task交给空闲线程. 否则执行(2) ;
- 当线程池为空或者没有空闲的线程, 则创建新的线程执行任务.;
- 执行完任务的线程倘若在60s内仍空闲, 则会被终止. 因此长时间空闲的CachedThreadPool不会持有任何线程资源。
-
newFixedThreadPool
创建⼀个定⻓线程池,可控制线程最⼤并发数,超出的线程会在队列中等待。(线程池的线程数量达corePoolSize后,即使线程池没有可执行任务时,也不会释放线程。)- 线程池里的线程数量不超过corePoolSize,这导致了maximumPoolSize和keepAliveTime将会是个无用参数;
- 由于使用了无界队列, 所以FixedThreadPool永远不会拒绝, 即饱和策略失效
-
newScheduledThreadPool
创建⼀个定⻓线程池,⽀持定时及周期性任务执⾏。 -
newSingleThreadExecutor
创建⼀个单线程化的线程池,它只会⽤唯⼀的⼯作线程来执⾏任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执⾏。如果该线程异常结束,会重新创建一个新的线程继续执行任务。
源码
// 构造器
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0) {
throw new IllegalArgumentException();
}
if (workQueue == null || threadFactory == null || handler == null) {
throw new NullPointerException();
}
this.acc = System.getSecurityManager() == null ? null : AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
CAPACITY的初始化
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
// runState is stored in the high-order bits
private static final int RUNNING = -1 << COUNT_BITS;
private static final int SHUTDOWN = 0 << COUNT_BITS;
private static final int STOP = 1 << COUNT_BITS;
private static final int TIDYING = 2 << COUNT_BITS;
private static final int TERMINATED = 3 << COUNT_BITS;
ctl含义(线程池运行状态和活动线程数)
ctl记录着workCount和runState。前3位是runState表示线程池运行状态,后29位是workCount表示线程池中当前活动的线程数。组成一个AtomicInteger对象。
// 初始化
// int是32位的,这里把int的高3位拿来充当线程池状态的标志位,后29位拿来充当当前运行worker的数量
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
/**
* 计算ctl的值
* ctl=[3位]线程池状态 + [29位]线程池中线程数量
*/
private static int ctlOf(int rs, int wc) {
return rs | wc; // 按位取或,即:同为0时为0,否则为1。此处可以理解为ctl内容的拼接
}
/**
* 获取运行状态 RUNNING/SHUTDOWN/STOP/TIDYING/TERMINATED
*/
private static int runStateOf(int c) {
// CAPACITY = 11100000000000000000000000000000
return c & ~CAPACITY;
}
/**
* 取出低位29位的值,表示获得当前活动的线程数
*/
private static int workerCountOf(int c) {
// CAPACITY = 00011111111111111111111111111111
return c & CAPACITY;
}
执行execute
// 执行
public void execute(Runnable command) {
if (command == null) {
throw new NullPointerException();
}
/** ctl记录着workCount和runState */
int c = ctl.get();
/** 第一步:如果线程池中的线程数量小于核心线程数,那么创建线程并执行*/
if (workerCountOf(c) < corePoolSize) { // workerCountOf(c): 获取当前活动的线程数
/**
* 在线程池中新建一个新的线程
* command:需要执行的Runnable线程
* true:新增线程时,【当前活动的线程数】是否 < corePoolSize
* false:新增线程时,【当前活动的线程数】是否 < maximumPoolSize
*/
if (addWorker(command, true)) {
// 添加新线程成功,则直接返回。
return;
}
// 添加新线程失败,则重新获取【当前活动的线程数】
c = ctl.get();
}
/** 第二步:如果当前线程池是运行状态 并且 任务添加到队列成功(即:case2: 如果workCount >= corePoolSize,创建线程往workQueue添加线程任务,等待执行)*/
// BlockingQueue<Runnable> workQueue 和 Runnable command
if (isRunning(c) && workQueue.offer(command)) { // 添加command到workQueue队列中。
// 重新获取ctl
int recheck = ctl.get();
// 再次check一下,当前线程池是否是运行状态,如果不是运行时状态,则把刚刚添加到workQueue中的command移除掉,并调用拒绝策略
if (!isRunning(recheck) && remove(command)) {
reject(command);
} else if (workerCountOf(recheck) == 0) { // 如果【当前活动的线程数】为0,则执行addWork方法
/**
* null:只创建线程,但不去启动
* false:添加线程时,根据maximumPoolSize来判断
*
* 如果 (workerCountOf(recheck) > 0, 则直接返回,在队列中的command稍后会出队列并且执行
*/
addWorker(null, false);
}
}
/**
* 第三步:满足以下两种条件之一,进入第三步判断语句
* 1. 线程池不是正在运行状态,即:isRunning(c)==false
* 2. workCount >= corePoolSize 并且 添加workQueue队列失败。即:workQueue.offer(command)==false
*
* 由于第二个参数传的是false,所以如果workCount < maximumPoolSize,则创建执行线程;否则,进入方法体执行reject(command)
*/
else if (!addWorker(command, false)) {
// 执行线程创建失败的拒绝策略
reject(command);
}
}
adWorker
/**
* @param firstTask 需要执行的Runnable线程
* @param core true:新增线程时,【当前活动的线程数】是否 < corePoolSize
* false:新增线程时,【当前活动的线程数】是否 < maximumPoolSize
*/
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
/**
* 步骤一:试图将workerCount+1
*/
for (; ; ) {
int c = ctl.get();
// 获得运行状态runState
int rs = runStateOf(c);
/**
* 只有如下两种情况可以新增worker,继续执行下去:
* case one: rs == RUNNING
* case two: rs == SHUTDOWN && firstTask == null && !workQueue.isEmpty()
*/
if (rs >= SHUTDOWN && // 即:非RUNNING状态(请查看isRunning()方法)。线程池异常,表示不再去接收新的线程任务了,返回false
/**
* 当线程池是SHUTDOWN状态时,表示不再接收新的任务了,所以:
* case1:如果firstTask!=null,表示要添加新任务,则:新增worker失败,返回false。
* case2:如果firstTask==null并且workQueue为空,表示队列中的任务已经处理完毕,不需要添加新任务了。则:新增worker失败,返回false
*/
!(rs == SHUTDOWN && firstTask == null && !workQueue.isEmpty())) {
return false;
}
for (; ; ) {
// 获得当前线程池里的线程数
int wc = workerCountOf(c);
/**
* 满足如下任意情况,则新增worker失败,返回false
* case1:大于等于最大线程容量,即:int CAPACITY = 00011111111111111111111111111111 = 536870911(十进制)
* case2:当core是true时:>= 核心线程数
* 当core是false时:>= 最大线程数
*/
if (wc >= CAPACITY || wc >= (core ? corePoolSize : maximumPoolSize)) {
return false;
}
// 当前工作线程数加1
if (compareAndIncrementWorkerCount(c)) {
break retry; // 成功加1,则跳出retry标识的这两层for循环
}
// 如果线程数加1操作失败,则获取当前最新的线程池运行状态
c = ctl.get();
// 判断线程池运行状态(rs)是否改变;如果不同,则说明方法处理期间线程池运行状态发生了变化,重新获取最新runState
if (runStateOf(c) != rs) {
continue retry; // 跳出内层for循环,继续从第一个for循环执行
}
}
}
/**
* 步骤二:workerCount成功+1后,创建Worker,加入集合workers中,并启动Worker线程
*/
boolean workerStarted = false; // 用于判断新的worker实例是否已经开始执行Thread.start()
boolean workerAdded = false; // 用于判断新的worker实例是否已经被添加到线程池的workers队列中
Worker w = null; // AQS.Worker
try {
// 创建Worker实例,每个Worker对象都会针对入参firstTask来创建一个线程。
w = new Worker(firstTask);
// 从Worker中获得新建的线程t
final Thread t = w.thread;
if (t != null) {
// 重入锁
final ReentrantLock mainLock = this.mainLock;
/** ----------lock() 尝试加锁操作!!获得锁后继续执行,没获得则等待直到获得锁为止---------- */
mainLock.lock();
try {
// 获得线程池当前的运行状态runStatus
int rs = runStateOf(ctl.get());
/**
* 满足如下任意条件,即可向线程池中添加线程:
* case1:线程池状态为RUNNING。(请查看isRunning()方法)
* case2:线程池状态为SHUTDOWN并且firstTask为null。
*/
if (rs < SHUTDOWN || (rs == SHUTDOWN && firstTask == null)) {
// 因为t是新构建的线程,还没有启动。所以,如果是alive状态,说明已经被启动了,则抛出异常。
if (t.isAlive()) {
throw new IllegalThreadStateException();
}
// workers中保存线程池中存在的所有work实例集合
workers.add(w);
int s = workers.size();
if (s > largestPoolSize) { // largestPoolSize用于记录线程池中曾经存在的最大的线程数量
largestPoolSize = s;
}
workerAdded = true;
}
} finally {
/** ----------unlock 解锁操作!!---------- */
mainLock.unlock();
}
if (workerAdded) {
/** 开启线程,执行Worker.run() */
t.start();
workerStarted = true;
}
}
} finally {
// 如果没有开启线程
if (!workerStarted) {
addWorkerFailed(w); // 往线程池中添加worker失败了
}
}
return workerStarted;
}
addWorkerFailed
/**
*回滚创建的工作线程
* 1> 从workers队列中移除worker(如果存在队列中的话)。
* 2> workerCount减一。
* 3> 重新检查是否终止(termination),以防止这个worker的存在阻止了终止(termination)
*/
private void addWorkerFailed(Worker w) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
if (w != null) {
workers.remove(w); // 步骤1:从work队列中移除w
}
// 步骤2:workerCount减1
decrementWorkerCount();
// 步骤3:
tryTerminate();
} finally {
mainLock.unlock();
}
}
tryTerminate
/**
* 如果(state是SHUTDOWN状态,并且线程池和队列都为空)或者(state是STOP状态,并且线程池和队列都为空),则将state状态转换为TERMINATED。
* 如果可以终止,但workerCount非零,则中断空闲的worker,以确保关闭信号传播。
* 必须在可能终止操作的任何操作之后调用此方法-减少worker计数或在关闭过程中从队列中删除任务。
* 该方法是非私有的,以允许从ScheduledThreadPoolExecutor访问。
*/
final void tryTerminate() {
for (; ; ) {
int c = ctl.get();
/**
* 只有runState=STOP 或 SHUTDOWN(且workQueue为空)才能继续往下执行
*/
if (isRunning(c) || // 判断c是否是RUNNING状态
runStateAtLeast(c, TIDYING) || // 判断c是否是TIDYING或者TERMINATED
(runStateOf(c) == SHUTDOWN && !workQueue.isEmpty())) { // 判断如果c是否是SHUTDOWN状态并且workQueue不为空
return;
}
// 当前活动的线程数不为0
if (workerCountOf(c) != 0) { // Eligible(有资格的) to terminate
// 因为ONLY_ONE=true,所以只针对一个闲置线程执行interrupt()
interruptIdleWorkers(ONLY_ONE);
return;
}
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) { // 尝试将当前线程池的运行状态设置为TIDYING,活跃线程数量设置为0
try {
terminated(); // 空方法
} finally {
ctl.set(ctlOf(TERMINATED, 0)); // 将当前线程池的运行状态设置为TERMINATED,活跃线程数量设置为0
termination.signalAll(); // 唤醒所有线程
}
return;
}
} finally {
mainLock.unlock();
}
}
}
interruptIdleWorkers
/**
* 中断可能正在等待任务的线程(如未锁定所示),以便它们可以检查终止或配置更改。
* 忽略SecurityExceptions(在这种情况下,某些线程可能保持不中断)。
*
* @param onlyOne 只中断一个闲置的线程
*/
private void interruptIdleWorkers(boolean onlyOne) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 循环线程池中存在的工作线程
for (Worker w : workers) {
Thread t = w.thread;
// 如果线程t没有被添加interrupt标识,并且w可以抢到锁(w为闲置的worker)
if (!t.isInterrupted() && w.tryLock()) {
try {
t.interrupt(); // 线程t在执行sleep、wait、join时,调用线程t的interrupt(),这时候t会有InterruptedException异常抛出来。
} catch (SecurityException ignore) {
} finally {
w.unlock();
}
}
if (onlyOne) {
break;
}
}
} finally {
mainLock.unlock();
}
}
runWorker
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
while (task != null || (task = getTask()) != null) {
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
/**
* 如果线程池正在停止,请确保线程被中断;否则,请确保线程不被中断。
* 这需要在第二种情况下重新检查以处理shutdownNow竞赛,同时清除中断
*
* 同时满足如下两个条件,则执行wt.interrupt()
* 1>线程状态为STOP、TIDYING、TERMINATED 或者 (当前线程被中断(清除中断标记)并且线程状态为STOP、TIDYING、TERMINATED)
* 2>当前线程wt没有被标记中断
*/
if ((runStateAtLeast(ctl.get(), STOP) || (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
如果 timed 为true,那么会一直take()取队列的任务,是阻塞的,这里就说明了核心线程默认是不会关闭的,会阻塞去队列数据直到队列中有数据。
private Runnable getTask() {
// 表示上次从阻塞队列中获取任务是否超时
boolean timedOut = false;
for (; ; ) {
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
/**
* 同时满足如下两点,则线程池中工作线程数减1,并返回null
*
* 1> rs >= SHUTDOWN,表示线程池不是RUNNING状态
* 2> rs >= STOP 表示STOP、TIDYING和TERMINATED这三个状态,它们共同点就是【不接收新任务】也【不处理workQueue里的线程任务】or 阻塞队列workQueue为空
*/
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount(); // 线程池中工作线程数减1
return null;
}
int wc = workerCountOf(c);
// timed用于判断是否需要进行超时控制,当allowCoreThreadTimeOut被设置为ture或者活跃线程数大于核心线程数,则需要进行超时控制
// allowCoreThreadTimeOut默认为false,则表明核心线程不允许超时
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
/**
* 同时满足以下两种情况,则线程池中工作线程数减1并返回null:
* case1:当前活动线程数workCount大于最大线程数,或者需要超时控制(timed=true)并且上次从阻塞队列中获取任务发生了超时(timedOut=true)
* case2:如果有效线程数大于1,或者阻塞队列为空。
*/
if ((wc > maximumPoolSize // 因为在执行该方法的同时被执行了setMaximumPoolSize,导致最大线程数被缩小
|| (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) { //
if (compareAndDecrementWorkerCount(c)) { // 线程池中工作线程数减1
return null;
}
// 如果减1失败,则循环重试
continue;
}
try {
// 如果需要超时控制,则通过阻塞队列的poll方法进行超时控制,
// 否则,直接获取,如果队列为空,task方法会阻塞直到队列不为空
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : // poll -->若队列为空,返回null
workQueue.take(); // take --> 若队列为空,发生阻塞,等待元素
if (r != null) {
return r;
}
// 如果r=null,表示超时了,则timeOut设置为true,标记为上一次超时状态
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
processWorkerExit
private void processWorkerExit(Worker w, boolean completedAbruptly) {
// 如果是由于用户异常导致worker死亡
if (completedAbruptly) {
decrementWorkerCount(); // 将workerCount减1
}
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 计算任务的完成数量
completedTaskCount += w.completedTasks;
// 将worker从线程池中移除
workers.remove(w);
} finally {
mainLock.unlock();
}
tryTerminate();
int c = ctl.get();
// runState是RUNNING或SHUTDOWN
if (runStateLessThan(c, STOP)) {
if (!completedAbruptly) {
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
if (min == 0 && !workQueue.isEmpty()) {
min = 1;
}
if (workerCountOf(c) >= min) {
return; // replacement not needed
}
}
addWorker(null, false);
}
}