常用方法
核心方法:execute
// command 是一个 Runnable 对象,也就是用户提交执行的任务
public void execute(Runnable command) {
// 提交的任务为空时抛出异常
if (command == null)
throw new NullPointerException();
/*
* Proceed in 3 steps:
*
* 1. If fewer than corePoolSize threads are running, try to
* start a new thread with the given command as its first
* task. The call to addWorker atomically checks runState and
* workerCount, and so prevents false alarms that would add
* threads when it shouldn't, by returning false.
*
* 2. If a task can be successfully queued, then we still need
* to double-check whether we should have added a thread
* (because existing ones died since last checking) or that
* the pool shut down since entry into this method. So we
* recheck state and if necessary roll back the enqueuing if
* stopped, or start a new thread if there are none.
*
* 3. If we cannot queue task, then we try to add a new
* thread. If it fails, we know we are shut down or saturated
* and so reject the task.
*/
// 获取当前 ctl (存有线程池状态和线程数量)
int c = ctl.get();
// 若当前工作线程数量小于核心池大小(coolPoolSize)
// 则在核心池中新增一个工作线程,并将该任务交给这个线程执行
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
// 重新获取(存在并发可能)
c = ctl.get();
}
// 若执行到这里,表示池中线程数量 >= corePoolSize,或者上面 addWorker 失败
// 若线程池处于 RUNNING 状态,并且该任务(command)成功添加到任务队列
if (isRunning(c) && workQueue.offer(command)) {
// 再次获取 ctl 值
int recheck = ctl.get();
// 若线程池不是运行状态,则要把上面添加的任务从队列中移除并执行拒绝策略
//(可理解为“回滚”操作)
if (! isRunning(recheck) && remove(command))
// 执行拒绝策略
reject(command);
// 若此时池中没有线程,则新建一个
// PS: 这里是防止任务提交后,池中没有存活的线程了
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
// 根据上述代码分析,若执行到这里,可分为以下两种情况:
// ① 线程池不是 RUNNING 状态;
// ② 线程池处于 RUNNING 状态,且实际线程数量 workCount >= corePoolSize,
// 并且,添加到 workQueue 失败(已满)
// 此时,则需要和 maximumPoolSize 进行比较,
// 若 workCount <= maximumPoolSize, 则新建一个线程去执行该任务;
// 否则,即 workCount > maximumPoolSize (饱和),则执行拒绝策略
else if (!addWorker(command, false))
// 执行拒绝策略
reject(command);
}
该方法描述的就是一个任务提交到线程池的流程,主要执行逻辑如下:
1、若正在运行的线程数少于 corePoolSize,则创建一个新的线程,并将传入的任务(command)作为它的第一个任务执行。
2、若运行的线程数不小于 corePoolSize,则将新来的任务添加到任务队列(workQueue)。若入队成功,仍需再次检查是否需要增加一个线程(上次检查之后现有的线程可能死了,或者进入该方法时线程池 SHUTDOWN 了,此时需要执行回滚);若池中没有线程则新建一个(确保 SHUTDOWN 状态也能执行队列中的任务)。
3、若任务不能入队(队列已满),则创建新的线程并执行任务,若失败(超过 maximumPoolSize),则表示线程池关闭或者已经饱和,因此拒绝该任务。
在线程池中,ctl 贯穿在线程池的整个生命周期中,它是一个原子类,主要作用是用来保存线程数量和线程池的状态。
内部类Worker及其方法:
// 继承自 AQS,且实现了 Runnable 接口
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable
{
/** 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;
// 初始化 thread
this.thread = getThreadFactory().newThread(this);
}
/** Delegates main run loop to outer runWorker */
public void run() {
runWorker(this);
}
// 其他一些 AQS 相关的方法不再一一列举
}
addWorker 方法:
在execute方法里可以看到这个方法,如果工作线程数小于核心线程数的话,会调用 addWorker,顾名思义,其实就是要创建一个工作线程。
// firstTask: 第一个任务,可为空
// core: 是否为核心池,true 是,false 为最大池
private boolean addWorker(Runnable firstTask, boolean core) {
// 该循环的主要作用就是增加 workCount 计数,增加成功后再新增 Worker 对象
retry://goto 语句,避免死循环
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
/*
* rs >= SHUTDOWN 表示线程池不再接受新的任务
* 该判断条件分为以下三种:
* ① 线程池处于 STOP, TYDING 或 TERMINATED 状态;
* ② 线程池处于 SHUTDOWN 状态,且 firstTask 不为空;
* ③ 线程池处于 SHUTDOWN 状态,且 workQueue 为空
* 满足任一条件即返回 false.
*/
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) {//自旋
int wc = workerCountOf(c);
// 超出最大容量 CAPACITY,或者超出初始设置的核心池/最大池数量,则返回 false
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
// CAS 方式增加 ctl 的 workerCount 数量(该循环的主要目的)
if (compareAndIncrementWorkerCount(c))
break retry; // 若增加失败则退出循环
c = ctl.get(); // Re-read ctl
// 运行状态改变
if (runStateOf(c) != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}
// 标记 Worker 是否启动、是否添加成功
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
// 将 firstTask 封装成 Worker 对象
w = new Worker(firstTask);
// 获取 thread 对象 t
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.
int rs = runStateOf(ctl.get());
// 若线程池状态小于 SHUTDOWN,即为 RUNNING 状态;
// 或者为 SHUTDOWN 状态,且 firstTask 为空,
// 表示不再接受新的任务,但会继续执行队列中的任务
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
// 添加到工作线程集合(HashSet)
workers.add(w);
// 更新最大计数
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
// 标记 Worker 添加成功
workerAdded = true;
}
} finally {
mainLock.unlock();
}
// 若成功添加到工作线程集合,则启动线程执行任务
if (workerAdded) {
// 启动线程
t.start();
workerStarted = true;
}
}
} finally {
// Worker 启动失败,执行回滚操作
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
addWorker 方法中,如果添加 Worker 并且启动线程失败,则会做失败后的处理。
private void addWorkerFailed(Worker w) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
if (w != null)
workers.remove(w);
decrementWorkerCount();
tryTerminate();
} finally {
mainLock.unlock();
}
}
runWorker 方法:
这个方法主要做几件事
1、如果 task 不为空,则开始执行 task
2、如果 task 为空,则通过 getTask()再去取任务,并赋值给 task,如果取到的 Runnable 不为空,则执行该任务
3、执行完毕后,通过 while 循环继续 getTask()取任务
4、如果 getTask()取到的任务依然是空,那么整个 runWorker()方法执行完毕
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
//unlock,表示当前 worker 线程允许中断,因为 new Worker 默认的 state=-1,此处是调用
//Worker 类的 tryRelease()方法,将 state 置为 0,
//而 interruptIfStarted()中只有 state>=0 才允许调用中断
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
//注意这个 while 循环,在这里实现了 [线程复用] // 如果 task 为空,则通过getTask 来获取任务
while (task != null || (task = getTask()) != null) {
w.lock(); //上锁,不是为了防止并发执行任务,为了在 shutdown()时不终止正在运行的 worker
//线程池为 stop 状态时不接受新任务,不执行已经加入任务队列的任务,还中断正在执行的任务
//所以对于 stop 状态以上是要中断线程的
//(Thread.interrupted() &&runStateAtLeast(ctl.get(), STOP)确保线程中断标志位为 true 且是 stop 状态以上,接着清除了中断标志
//!wt.isInterrupted()则再一次检查保证线程需要设置中断标志位
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
beforeExecute(wt, task);//这里默认是没有实现的,在一些特定的场景中我们可以自己继承 ThreadpoolExecutor 自己重写
Throwable thrown = null;
try {
task.run(); //执行任务中的 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,需要再通过 getTask()取) + 记录该 Worker 完成任务数量 + 解锁
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly);
//1.将入参 worker 从数组 workers 里删除掉;
//2.根据布尔值 allowCoreThreadTimeOut 来决定是否补充新的 Worker 进数组workers
}
}

本文详细解析了线程池的任务提交执行过程,包括任务分配、线程创建、任务队列管理及异常处理机制等关键步骤。
428

被折叠的 条评论
为什么被折叠?



