线程池初解2
前言
本次介绍的是ThreadPoolExecutor,ThreadPoolExecutor
是ExecutorService
接口的一个具体实现类,用于创建和管理线程池。ThreadPoolExecutor
提供了丰富的参数和配置选项,可以根据需要进行灵活的定制。
源码解析
构造函数
该线程池提供了多个构造函数,核心的构造函数只有一个
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
public ThreadPoolExecutor(int corePoolSize, //核心线程数量
int maximumPoolSize, //最大线程数量
long keepAliveTime, //当线程数大于核心数时,这是多余的空闲线程在终止之前等待新任务的最长时间。
TimeUnit unit, //参数的时间 keepAliveTime 单位
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;
}
总结
-
corePoolSize为线程池的核心线程数,当线程池的线程个数小于核心线程数时,每次提交新任务都会创建新的线程来执行(即使有空闲线程)
-
maximumPoolSize,该线程池的最大线程数
-
keepAliveTime。当线程数大于核心线程数时,这是多余的空闲线程在终止之前等待新任务的最长时间
-
unit keepAliveTime的等待时间单位
-
workQueue 任务队列(阻塞队列),当核心线程数满时,再次提交新任务会将该任务放到此任务队列中
-
threadFactory 线程工厂 ,创建线程的工厂
-
handler 拒绝策略 当线程池最大线程数已满,任务队列已满 当有任务提交时,会调用此拒绝策略处理任务(当线程池被停止时不再接受新任务,也会调用拒绝策略处理任务)ThreadPoolExecutor定义了四种拒绝策略
-
拒绝策略默认为 AbortPolicy 直接抛出异常
public static class AbortPolicy implements RejectedExecutionHandler { /** * Creates an {@code AbortPolicy}. */ public AbortPolicy() { } /** * Always throws RejectedExecutionException. * * @param r the runnable task requested to be executed * @param e the executor attempting to execute this task * @throws RejectedExecutionException always */ public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { throw new RejectedExecutionException("Task " + r.toString() + " rejected from " + e.toString()); } }
-
CallerRunsPolicy 提交任务的线程执行此任务
public static class CallerRunsPolicy implements RejectedExecutionHandler { /** * Creates a {@code CallerRunsPolicy}. */ public CallerRunsPolicy() { } /** * Executes task r in the caller's thread, unless the executor * has been shut down, in which case the task is discarded. * * @param r the runnable task requested to be executed * @param e the executor attempting to execute this task */ public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { r.run(); } } }
-
DiscardPolicy 什么也不做 直接丢弃
public static class DiscardPolicy implements RejectedExecutionHandler { /** * Creates a {@code DiscardPolicy}. */ public DiscardPolicy() { } /** * Does nothing, which has the effect of discarding task r. * * @param r the runnable task requested to be executed * @param e the executor attempting to execute this task */ public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { } }
-
DiscardOldestPolicy 清除任务队列中等待时间最长的任务,执行此任务
public static class DiscardOldestPolicy implements RejectedExecutionHandler { /** * Creates a {@code DiscardOldestPolicy} for the given executor. */ public DiscardOldestPolicy() { } /** * Obtains and ignores the next task that the executor * would otherwise execute, if one is immediately available, * and then retries execution of task r, unless the executor * is shut down, in which case task r is instead discarded. * * @param r the runnable task requested to be executed * @param e the executor attempting to execute this task */ public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { e.getQueue().poll(); e.execute(r); } } }
-
线程池工作流程
- 当有新任务提交时,首先判断当前线程池的线程数是否已经达到核心线程数,如果没有则创建新线程去处理任务(即使有空闲的线程)
- 核心线程数已满,判断任务队列是否已满,如果任务队列未满,则将任务放入到任务队列中
- 如果任务队列已满,则判断当前线程数是否已经达到最大线程数,未达到则创建新线程去处理任务
- 如果任务队列和最大线程数都已经满了,则使用拒绝策略处理任务
- 当任务执行完,线程会从任务队列中拿取任务并执行。
- 当所有的任务都执行完,线程会在keepAliveTime时间后销毁,直到线程数数量达到核心线程数
线程池状态
- RUNNING 运行状态,接收新任务并处理阻塞队列里的任务
- SHUTDOWN 拒绝新任务 但是处理阻塞队列里的任务
- STOP 拒绝新任务,并抛弃阻塞队列里的任务,中断正在处理的任务
- TIDYING 是一个过渡状态,
- 在SHUTDOWN状态下,工作线程为空,并且任务队列为空则过渡到TIDYING状态
- 在STOP状态下,工作线程为空则过渡到TIDYING状态
- TERMINATED 终止状态terminated方法调用完成以后的状态 TIDYING->TERMINATED terminated方法是一个钩子方法。表示线程池结束时调用的方法
线程池状态的表示方式
//线程池的状态和线程数量表示 使用高3位表示当前线程池状态,低29位表示当前线程池线程数量
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); //线程池默认处于运行状态,线程数量为0
//数量的位数 29 Integer.SIZE = 32
private static final int COUNT_BITS = Integer.SIZE - 3;
//线程池最大线程个数 00011111 11111111 11111111 11111111
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
// runState is stored in the high-order bits
//将二进制数向左移位操作,高位溢出则丢弃,低位补0
//-1是 32个1(补码表示) 左移29位后 11100000 00000000 00000000 00000000
private static final int RUNNING = -1 << COUNT_BITS; //运行状态,接收新任务并处理阻塞队列里的任务
//00000000 00000000 00000000 00000000
private static final int SHUTDOWN = 0 << COUNT_BITS; //拒绝新任务 但是处理阻塞队列里的任务
//00100000 0000000 00000000 00000000
private static final int STOP = 1 << COUNT_BITS; //拒绝新任务,并抛弃阻塞队列里的任务,中断正在处理的任务
//01000000 0000000 00000000 00000000
private static final int TIDYING = 2 << COUNT_BITS;//所有任务都执行完(包含阻塞队列里的任务)后当前线程后动线程数为0,将调用terminated方法 STOP -> TIDYING 或者SHUTDOWN -> TIDYING
//01100000 0000000 00000000 00000000
private static final int TERMINATED = 3 << COUNT_BITS;//终止状态terminated方法调用完成以后的状态 TIDYING->TERMINATED
// Packing and unpacking ctl 获取运行时状态 高三位
//~CAPACITY = 11100000 00000000 00000000 00000000
private static int runStateOf(int c) { return c & ~CAPACITY; }
// 获取低29位 线程数量
private static int workerCountOf(int c) { return c & CAPACITY; }
//计算ctl值 rs为线程池状态 wc线程池线程数量
private static int ctlOf(int rs, int wc) { return rs | wc; }
execute(Runnable command)方法
public void execute(Runnable command) {
//判断要执行的任务不能为空
if (command == null)
throw new NullPointerException();
/**
* 分 3 个步骤进行:
* 1. 如果运行的线程数少于 corePoolSize,请尝试使用给定的命令作为其第一个任务来启动一个新线程。
* 对 addWorker 的调用以原子方式检查 runState 和 workerCount,从而通过返回 false 来防止在不应该添加线程时添加线程的误报。
* 2. 如果一个任务可以成功排队,那么我们仍然需要仔细检查我们是否应该添加一个线程(因为现有的线程自上次检查以来就死了),
* 或者池在进入此方法后关闭了。因此,我们重新检查状态,并在必要时回滚排队(如果已停止),或者在没有线程时启动新线程。
* 3.如果我们无法对任务进行排队,那么我们尝试添加一个新线程。如果它失败了,我们知道我们被关闭或饱和,因此拒绝该任务。
*/
//获取线程池的状态和线程池线程数量字段
int c = ctl.get();
//如果线程数量小于核心线程数
if (workerCountOf(c) < corePoolSize) {
//增加一个工作线程执行该任务 command作为firstTask
if (addWorker(command, true))
//添加成功直接返回
return;
//重新获取线程池的状态和线程池线程数量字段
c = ctl.get();
}
//核心线程数已满
//线程属于正在运行状态 并且将command命令放入任务队列成功了(任务队列未满)
if (isRunning(c) && workQueue.offer(command)) {
//重现校验线程池状态和线程数量
int recheck = ctl.get();
//如果不是运行状态则不接受当前命令(不接受新任务),删除命令任务队列中的任务
if (!isRunning(recheck) && remove(command))
//拒绝策略调用
reject(command);
//
else if (workerCountOf(recheck) == 0)
//工作线程数量为0了但是 任务队列中还有任务 新建一个线程去处理任务队列中的任务
addWorker(null, false);
}
//队列已满 并且核心线程也到达指定数量,则直接创建一个新线程处理该任务,创建失败,则使用饱和策略处理拒绝任务
else if (!addWorker(command, false))
//饱和策略调用
reject(command);
}
总结
- 判断核心线程数是否已满,没满则创建新线程执行该任务
- 核心线程数已满,如果正处于运行状态,并且将任务放到队列成功
- 再次判断线程池状态,不是运行状态,则删除队列任务,调用拒绝策略
- 判断线程池线程数量,如果为0则新建线程处理队列中的任务
- 核心线程数和任务队列均已满 或者 线程池处于非运行状态 调用饱和策略
- 核心线程数和任务队列均已满 新增线程处理任务(addWorker方法在线程数量达到最大线程数时调用失败)
- 线程池处于非运行状态 (addWorker方法在线程池队列处于非运行状态时调用失败)
Worker类
//Worker集合 保存当前线程池的线程
private final HashSet<Worker> workers = new HashSet<Worker>(); //线程池里的线程
//Worker封装了线程池的工作线程,可以认为一个Worker就是一个工作线程
private final class Worker
//继承了AQS 重写了tryAcquire、tryRelease、isHeldExclusively
//实现AQS是为了线程在初始过程中不可被中断
extends AbstractQueuedSynchronizer
//实现了Runnable
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) {
//设置锁状态初始状态为-1
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
//线程工厂新建一个线程
this.thread = getThreadFactory().newThread(this);
}
/** Delegates main run loop to outer runWorker */
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); }
//锁已经是否被获取 AQS state为1表示已经获取到锁 0表示未获取到 -1表示初始状态
public boolean isLocked() { return isHeldExclusively(); }
void interruptIfStarted() {
Thread t;
// -1状态不会被中断
if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
}
}
}
}
addWorker(Runnable firstTask, boolean core)方法
此方法分为两个部分
- ctl字段线程池线程数量字段+1
- 新增并启动一个工作线程
//新增任务线程
private boolean addWorker(Runnable firstTask, boolean core) {
/**********************************************ctl字段线程池线程数量字段+1 *********************************/
retry:
for (;;) { //自旋 修改ctl+1 线程池中线程数量加一
int c = ctl.get();
/***************************线程池状态判断*********************************/
//线程池状态
int rs = runStateOf(c);
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN && //线程处于非运行状态
//当线程池处于SHUTDOWN状态可以处理任务队列中的任务,如果线程池线程为空,任务队列不为空
//可以新增一个firstTask为null的线程处理任务队列中的任务
!(rs == SHUTDOWN && firstTask == null && !workQueue.isEmpty())
)
return false; //返回创建线程失败
/***************************线程池数量判断*********************************/
//自旋 增加当前线程池线程数量
for (;;) {
//获取工作线程数量
int wc = workerCountOf(c);
//工作线程数量大于最大线程数 或者增加的线程时核心线程但是核心线程已满 或者maximumPoolSize已满直接返回false
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false; //数量校验失败返回创建工作线程失败
if (compareAndIncrementWorkerCount(c)) //CAS增加线程个数 失败则重试(状态或者线程数被改变了)
break retry; //成功跳转到retry 跳出外层循环
c = ctl.get(); // Re-read ctl 重新获取
if (runStateOf(c) != rs) //线程池状态已经被改变 跳转到retry 继续状态的判断 状态没有改变就继续自旋修改数量
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}
/**********************************************新增并启动一个工作线程*********************************/
//工作线程是否启动标识
boolean workerStarted = false;
//工作线程是否已经添加到线程set成功标识
boolean workerAdded = false;
Worker w = null;
try {
//新建一个worker
w = new Worker(firstTask);
//新建的线程
final Thread t = w.thread;
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.
//获取锁成功后重新检查线程池状态,有可能在获取锁之前调用了shutdown关闭线程池
int rs = runStateOf(ctl.get());
//两种情况 1.线程池正处于运行状态 2.线程池正处于SHUTDOWN状态且firstTask为空(用于处理任务队列中的任务)
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
//如果线程已经处于活动状态 执行了start方法 说明此线程已经独立运行
if (t.isAlive()) // precheck that t is startable 预先检查t是否可启动
throw new IllegalThreadStateException();
//将新创建的worker 添加到workers集合中
workers.add(w);
//workers集合中的线程数量
int s = workers.size();
if (s > largestPoolSize)
//赋值线程池中出现过的最大的线程数
largestPoolSize = s;
//添加成功
workerAdded = true;
}
} finally {
mainLock.unlock();
}
//线程添加成功
if (workerAdded) {
//启动线程
t.start();
//已启动
workerStarted = true;
}
}
} finally {
//工作线程启动或添加失败
if (!workerStarted)
//工作线程没有启动
addWorkerFailed(w);
}
//返回工作线程是否启动
return workerStarted;
}
//增加工作线程失败
private void addWorkerFailed(Worker w) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
if (w != null)
workers.remove(w); //workeds里移除对应worker
decrementWorkerCount(); //递减线程池工作线程数量
tryTerminate(); //尝试终止 重新检查是否终止,以防该worker的存在阻碍了终止
} finally {
mainLock.unlock();
}
}
runWorker(Worker w)方法
新建的线程中的target对象为新建的worker,当线程启动时调用worker的run方法为runWorker(Worker w)
final void runWorker(Worker w) {
//获取当前线程 w.thread
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();
//1.如果线程处于STOP状态并且线程没有处于中断状态则中断该线程
//2.如果线程不处于STOP状态,但是线程处于中断状态,则清除中断标识
// private static boolean runStateAtLeast(int c, int s) {
// return c >= s;
// }
if ((runStateAtLeast(ctl.get(), STOP) || (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP)))
&& !wt.isInterrupted())
wt.interrupt(); //中断线程
try {
//任务执行前钩子函数
beforeExecute(wt, task);
Throwable thrown = null;
try {
//执行任务(默认就是FutureTask的run方法)
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();
}
}
//当在任务队列中获取任务,返回为空时走到这里(线程根据keepAliveTime等待任务超时,且当前线程数大于核心线程数会返回任务为null)
completedAbruptly = false;
} finally {
//completedAbruptly = true 表示该线程异常退出
//completedAbruptly = fasle 表示该线程正常退出
processWorkerExit(w, completedAbruptly);
}
}
processWorkerExit(Worker w, boolean completedAbruptly)方法
在工作线程退出后执行此方法,Worker执行结束后的清理工作或其他逻辑 completedAbruptly为true表示异常退出,completedAbruptly为false表示正常退出
- 将工作线程从线程池的HashSet集合中移除
- 尝试结束线程池
- 判断SHOWDOWN状态下是否还有线程去处理任务队列中的任务
private void processWorkerExit(Worker w, boolean completedAbruptly) {
//工作线程异常退出 将线程池的工作线程数量减一
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();
// private static boolean runStateLessThan(int c, int s) {
// return c < s;
// }
if (runStateLessThan(c, STOP)) { //处于运行或者shotdown状态(都需要处理任务队列中的任务)
//工作线程正常退出
if (!completedAbruptly) {
//计算当前线程池需要的最小的线程数
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
//如果任务队列中还有任务 需要有线程去处理
if (min == 0 && ! workQueue.isEmpty())
//则最小的线程数为1
min = 1;
if (workerCountOf(c) >= min)
return; // replacement not needed
}
//1.工作线程异常退出
//2.任务队列中还有任务需要去执行,但是线程池中已经没有线程需要新建一个
//3.核心线程不会被销毁,当前线程数小于核心线程数则创建新的工作线程
addWorker(null, false);
}
}
getTask()方法
当工作线程的第一个任务完成后会去任务队列中获取任务执行,此方法为获取任务的方法
根据当前配置设置对任务执行阻塞或定时等待,或者如果此工作线程由于以下任何原因必须退出,则返回 null:
- 有超过 maximumPoolSize 工作线程(由于调用 setMaximumPoolSize)。
- 线程池已关闭。(STOP状态)
- 线程池处于SHUTDOWN状态,并且任务队列为空
- 此工作线程在等待任务时超时,超时工作线程在定时等待之前和之后都会被终止(即 allowCoreThreadTimeOut || workerCount > corePoolSize),如果队列不为空,则此工作线程不是池中的最后一个线程。
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.
//1.线程池处于STOP状态不在处理任务队列中的任务直接返回null
//2.线程池处于SHUTDOWN状态但是任务队列为空了返回null
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
//线程池线程数量减1 表明此线程要被销毁(调用processWorkerExit方法处理工作线程的清除)
decrementWorkerCount();
return null; //返回空
}
/*************************************判断线程池线程数量**************************************/
//工作线程数量
int wc = workerCountOf(c);
// 当前线程是否需要根据keepAliveTime时间超时销毁 1.设置了核心线程需要被清除则所有线程都需要被清除2.当前线程数量大于核心线程数
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
// 1.当前线程数量大于设置的最大线程数(不会成立) 并且 此线程不是最后的线程或者任务队列为空则可以清除此线程
// 2.该线程需要被清除(当前线程数量大于核心线程数或者设置了核心线程也被清除)并且 在任务队列中等待任务已经超时(超过keepAliveTime)
//并且 此线程不是最后的线程或者任务队列为空则可以清除此线程
if ((wc > maximumPoolSize || (timed && timedOut)) //非核心线程超过了存活时间获取不到任务
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c)) //线程池线程数量减一
return null;
continue;
}
/*************************************执行获取任务**************************************/
try {
// timed 表示当前线程是否需要根据keepAliveTime时间超时销毁
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
timedOut = true; //超时后 第二次循环如果当前线程数大于核心线程数则会被清除
//正在等待任务列表的任务在阻塞的过程中因为 线程池被shutdown或者shoutdownNow则会捕获抛出的中断异常 再次循环判断状态时会将此线程销毁
} catch (InterruptedException retry) {
timedOut = false; //中断
}
}
}
总结
- 线程池中的线程没有核心线程与非核心线程的标识区别 是根据当前线程池的线程数量与设置的线程池核心线程池作比较判断当前线程是否需要在等待keepAliveTime时间后销毁
- keepAliveTime时间是根据阻塞队列,在阻塞队列中获取任务超时后则销毁此线程 poll(keepAliveTime, TimeUnit.NANOSECONDS)
- 核心线程的阻塞时在任务队列中获取任务时take方法阻塞
shutdown()方法
修改当前线程池为shutdown状态不接受新任务,但是需要处理任务队列中的任务
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
//校验权限
checkShutdownAccess();
//将线程池状态改为SHOTDOWN状态
advanceRunState(SHUTDOWN);
//中断正在等待的线程
interruptIdleWorkers(); //interruptIdleWorkers(false);
onShutdown(); // hook for ScheduledThreadPoolExecutor 调用shutdown()方法的钩子函数
} finally {
mainLock.unlock();
}
tryTerminate();
}
//将 runState 转换为给定目标,如果至少已经是给定目标,则忽略
private void advanceRunState(int targetState) {
for (;;) {
int c = ctl.get();
if (runStateAtLeast(c, targetState) ||
ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
break;
}
}
//onlyOne如果为 true,则最多中断一个工作线程
private void interruptIdleWorkers(boolean onlyOne) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock(); //加锁
try {
//遍历中断线程
for (Worker w : workers) {
Thread t = w.thread;
//如果线程没有处于中断状态并且处于等待状态则中断线程
if (!t.isInterrupted() && w.tryLock()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
} finally {
w.unlock();
}
}
if (onlyOne)
break;
}
} finally {
mainLock.unlock();
}
}
shutdownNow()方法
public List<Runnable> shutdownNow() {
List<Runnable> tasks;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
//校验权限
checkShutdownAccess();
//将线程池状态改为SHOTDOWN状态
advanceRunState(STOP);
//中断所有线程
interruptWorkers();
//清空任务列表并返回新的任务列表
tasks = drainQueue();
} finally {
mainLock.unlock();
}
tryTerminate();
//返回未执行的任务列表
return tasks;
}
//中断所有线程
private void interruptWorkers() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers)
w.interruptIfStarted();
} finally {
mainLock.unlock();
}
}
//将任务队列排空到新列表中,通常使用 drainTo。
//但是,如果队列是 DelayQueue 或任何其他类型的队列,而 poll 或 drainTo 可能无法删除某些元素,则它会逐个删除它们。
private List<Runnable> drainQueue() {
//任务列表
BlockingQueue<Runnable> q = workQueue;
ArrayList<Runnable> taskList = new ArrayList<Runnable>();
//从此队列中删除所有可用元素,并将它们添加到给定集合中。
q.drainTo(taskList);
if (!q.isEmpty()) {
for (Runnable r : q.toArray(new Runnable[0])) {
if (q.remove(r))
taskList.add(r);
}
}
return taskList;
}
tryTerminate()方法
//1.线程池处于SHUTDOWN状态并且任务队列为空工作线程为空
//2.线程池处于STOP状态并且工作线程为空
//则转换为TERMINATED状态
//如果符合终止条件,但 workerCount 不为零,则中断空闲工作线程以确保关闭信号传播。
//此方法必须在执行任何可能终止的操作之后调用 - 减少工作线程计数或在关闭期间从队列中删除任务
final void tryTerminate() {
for (;;) {
int c = ctl.get();
//1.线程池处于运行状态
//2.线程池TIDYING或TERMINATED状态
//3.线程处于SHUTDOWN状态并且任务队列不为空
//以上几种情况则直接返回
if (isRunning(c) ||
runStateAtLeast(c, TIDYING) ||
(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
return;
//线程数量不为0
if (workerCountOf(c) != 0) { // Eligible to terminate
//中断一个等待线程 则中断线程会退出,线程退出后(processWorkerExit方法)会调用尝试tryTerminate终止线程池
interruptIdleWorkers(ONLY_ONE);
return;
}
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
//将线程池状态设置为TIDYING状态,线程池数量为0
if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
try {
terminated(); //线程池终止的钩子方法
} finally {
将线程池状态设置为TERMINATED状态,线程池数量为0
ctl.set(ctlOf(TERMINATED, 0));
termination.signalAll(); //通知等待线程池终止的线程
}
return;
}
} finally {
mainLock.unlock();
}
// else retry on failed CAS
}
}
mainLock总结
- 新建工作线程,将工作线程放入HashSet中需要加锁,HashSet是线程不安全的 包括 largestPoolSize字段赋值
- 新建工作线程失败,将工作线程从HashSet中删除需要加锁
- 工作线程退出后,修改线程池的总共完成的任务数需要加锁
- shutdown()方法需要加锁操作
- shutdownNow()方法需要加锁操作
- 中断等待线程的时候需要加锁
- 中断所有线程的时候需要加锁
- 终止线程池时需要加锁tryTerminate方法