1、execute(Runnable command) 方法
execute() 方法是线程池 ThreadPoolExecutor 中最核心的方法,由前边的
AbstractExecutorService 类可以知道 执行 submit() 方法向线程池提交任务时,提交任务
的操作最终还是由execute() 来完成,如下图所示:

execute() 方法执行时有4种情况,即:
1)如果当前运行的线程少于核心线程数corePoolSize,则创建新的线程来执行当前提交
的任务,执行这一步骤需要获取全局锁
2)如果当前运行的线程数等于或大于核心线程数corePoolSize,则将当前提交的任务放入
BlockingQueue阻塞队列中
3)如果无法将当前提交的任务放入BlockingQueue(即队列已满),但运行的线程数小于
最大线程数maximumPoolSize,则创建新的线程来处理任务,执行这一步骤需要获取
全局锁
4)如果当前运行的线程数已经到达最大线程数 maximumPoolSize,则调用
RejectedExecutionHandler.rejectedExecution() 处里该任务;
若使用默认的 RejectedExecutionHandler,任务将被拒绝(默认拒绝策略是直接拒
绝任务)
execute() 方法执行流程图如下:

ThreadPoolExecutor 采用上述步骤的设计思路是为了执行execute()方法时,尽量避免
获取全局锁;当ThreadPoolExecutor 中运行的线程数大于 corePoolSize 时,几乎所有
的execute() 方法调用都是执行步骤2,步骤2不需要获取全局锁。
execute() 方法代码如下:
/**
*
* 执行给定的任务,这个任务可以在新线程中执行,也可以在线程池中已存在的线程中执行
*
* 如果任务不能提交执行,可能是因为这个原因执行程序已关闭或已达到容量,
* 该任务由当前的{@code RejectedExecutionHandler}处理。
*
*/
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/*
*
* 执行线程任务按3个步骤执行:
* 1、如果线程池中少于corePoolSize线程运行,尝试启动一个新的线程与给定的命令作为它的第一个任务线程。
* 对addWorker的调用会自动检查runState和 workerCount,因此通过返回false来防止误报,
* 因为误报会在不应该添加线程的时候添加线程。
*
* 2、如果一个任务可以成功地进入队列,那么我们仍然需要再次检查我们是否应该添加一个线程(因为现有的线程在上次检查后死亡),
* 或者池在进入这个方法后关闭。因此,我们重新检查状态,并在停止时回滚队列,或者在没有线程时启动一个新线程。
*
* 3、如果不能把任务添加到队列中,则尝试添加一个新的线程。如果它失败了,我们知道我们已经关闭或饱和了
*,因此拒绝任务。
*/
//重新获取线程数
int c = ctl.get();
//1、如果线程池中的线程总数小于设置的核心线程数 corePoolSize,
//则创建一个新的线程去执行 command
//一个worker 其实就是一个线程,包含需要执行的任务command,其实任务也是一个线程
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))//启动新的线程成功(即核心线程没满),则直接结束
return;
//重新获取线程数,
// 若 addWorker 执行失败,那么此时ctl可能被更新了,所以需要获取
c = ctl.get();
}
//核心线程数满了,试着将任务线程放入工作队列
if (isRunning(c) && workQueue.offer(command)) {//2、线程池处于运行状态且任务队列没有满,任务command入队列成功
//复查线程池是否是运行状态(预防别人任务关闭线程池)
int recheck = ctl.get();
//若线程池非处在运行状态,即线程池关闭了,且任务command 已经位于工作队列中(可以成功从队列中删除,即在进入execute 方法后线程池关闭了)
//,则把任务 command 交给拒绝策略执行
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)//核心线程数空了,允许核心线程数释放资源,这个是临界情况
//启动一个新的线程,该线程没有绑定任务,实际中基本不存在这种情况
addWorker(null, false);
}
else if (!addWorker(command, false))//3、线程池已经饱和(即线程数达到最大线程数,工作队列也已经满了)或线程池关闭了,则把该任务交给拒绝策略执行
reject(command);
}
2、addWorker(Runnable firstTask, boolean core)
addWorker 主要功能是通过Worker 创建线程并修改线程池工作线程的个数,
firstTask-- 新线程首先运行的任务(如果没有,则为 null)。
worker被创建为一个初始化的first task (在方法execute()中),当少于corePoolSize
线程(在这种情况下,我们总是启动一个),或当队列是满的(在这种情况下,我们必
须绕过队列)。初始空闲线程通常是通过prestartCoreThread创建的,或者用来替
换其他垂死的工作线程。
core-- 如果为true,则使用corePoolSize作为绑定(即把任务firstTask设置为核心线程,并立
即执行),否则maximumPoolSize。(这里使用布尔指示符而不是在检查其他池后,
确保读取新的值状态)。
addWorker 方法代码如下:
private boolean addWorker(Runnable firstTask, boolean core) {
/**
* 创建 Worker
*/
retry:
/*
* 先去增加线程池中线程总数
* 使用循环的原因可能第一次线程池满了,添加不进去,后面第二次进入循环后,线程池有执行结束的工作线程,就可以增加成功了。
*
* 判断线程池状态,添加线程数
*/
for (;;) {
//获取当前线程池中线程数
int c = ctl.get();
//返回线程池是否是运行状态值,
int rs = runStateOf(c);
// 仅在必要时检查队列是否为空
if (rs >= SHUTDOWN && //表示线程池处于非运行状态
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))//若当前线程池状态是 非运行状态 且(若当前是SHUTDOWN 状态 且 firstTask第一个任务为null且工作队列不为空)=false,则添加工作器worker 失败
//若工作队列不为null,则线程池活动的线程数可能会大于核心线程数,若工作队列为null,则会线程数小于或等于核心线程数
return false;
//修改(即增加线程的个数)
for (;;) {
//获取工作器(每个工作器worker表示一个工作线程)的总数,即当前线程池中线程的总数
int wc = workerCountOf(c);
//若当前线程的总数大于设定的最大值 CAPACITY 或大于 构造函数中设定的值(corePoolSize 或 maximumPoolSize),
//则添加失败,直接返回false
//core=true: 表示该线程是核心线程,否则该线程作为普通线程,
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))//core=true: 使用线程池的核心线程数来判断,core=false:使用线程池的最大线程数来判断
return false;
//若将当前线程池的状态ctl修改成功(即线程数加1),则跳出循环到 retry 处,否则进入下一循环看总的线程数是否减少(即是否有线程执行完结束了)
//增加 ctl的值,
if (compareAndIncrementWorkerCount(c))
break retry;
//获取ctl 的值
c = ctl.get(); // Re-read ctl
//若 ctl 的值被修改了,则跳出本次循环
if (runStateOf(c) != rs)
continue retry;
// CAS失败,由于workerCount变化;重试内循环
}
}
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
//将任务线程封装成 worker,创建线程
w = new Worker(firstTask);
//获取通过ThreadFactory 构建的线程,
// 其实也是当前的工作线程,只是装饰一下
final Thread t = w.thread;
if (t != null) {
//获取显式锁对象
final ReentrantLock mainLock = this.mainLock;
//加锁
mainLock.lock();
try {
// 锁定时重新价差
// 锁在 ThreadFactory 失败时或 在 lock acquired 之前关闭时退出
int rs = runStateOf(ctl.get());//获取ctl 的值
if (rs < SHUTDOWN || //线程池状态小于SHUTDOWN,即当前线程池处于运行中状态
(rs == SHUTDOWN && firstTask == null)) {//当前线程池状态等于 SHUTDOWN,且 任务线程为null
if (t.isAlive()) // precheck that t is startable 预检查 t 是可以启动的,则抛出线程状态异常
throw new IllegalThreadStateException();
//添加worker,即添加工作线程到 集合workers
workers.add(w);
//获取所有的工作线程
int s = workers.size();
//更新 largestPoolSize
if (s > largestPoolSize)
largestPoolSize = s;
//设置添加成功
workerAdded = true;
}
} finally {
//释放锁
mainLock.unlock();
}
if (workerAdded) {
//工作线程添加成功后,启动当前工作线程
/**
* todo 注意:
* 这里真正执行的就是 Worker 的run() 方法
*/
t.start();
//设置启动成功
workerStarted = true;
}
}
} finally {
//启动失败,将工作线程从 集合workers 中删除,并将ctl自减
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
3、reject(Runnable command)
reject 表示调用拒绝策略,来处理拒绝的任务;线程池中的拒绝策略请参考前边的内容
reject 方法定义如下:
/**
* 为指定程序调用的被拒绝的执行处理程序。包保护,由ScheduledThreadPoolExecutor使用。
*/
final void reject(Runnable command) {
//拒绝策略
handler.rejectedExecution(command, this);
}
4、addWorkerFailed(Worker w)
addWorkerFailed 用来回滚addWorker 中创建的工作线程
addWorkerFailed 代码如下:
/**
* 回滚创建的工作线程。
*/
private void addWorkerFailed(Worker w) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
if (w != null)
workers.remove(w);
//减少ctl的值
decrementWorkerCount();
//更新线程池状态
tryTerminate();
} finally {
mainLock.unlock();
}
}
private void decrementWorkerCount() {
//减少ctl的值。这只在线程突然终止时被调用(参见processWorkerExit)。其他减量在getTask中执行。
do {} while (! compareAndDecrementWorkerCount(ctl.get()));
}
5、tryTerminate()
tryTerminate 方法主要功能是,如果(SHUTDOWN和池和队列为空)或(STOP和池为空),
则转换到终止状态。如果符合终止条件,但workerCount非零,则中断一个空闲的工作器,
以确保关闭信号传播。这个方法必须在任何可能导致终止的操作之后被调用——减少工作
人员的数量或在关机期间从队列中删除任务。
该方法是非私有的,允许从ScheduledThreadPoolExecutor访问。
tryTerminate 方法代码如下:
final void tryTerminate() {
//自旋
for (;;) {
//获取线程池状态
int c = ctl.get();
//若线程池是在运行状态 或 TIDYING 状态 或 SHUTDOWN状态且工作队列不为空,则不能将线程池转换为终止状态,终止往下执行
if (isRunning(c) ||
runStateAtLeast(c, TIDYING) ||
(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
return;
//判断释放可以中止的工作器worker,若worker 不为0,则只中断一个空闲的工作器
if (workerCountOf(c) != 0) { // Eligible to terminate
//中断一个工作器(即一个工作线程)
interruptIdleWorkers(ONLY_ONE);
return;
}
// 上面的条件不满足,
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
try {
// 钩子函数
terminated();
} finally {
ctl.set(ctlOf(TERMINATED, 0));
//唤醒所有的任务线程,在这里启动阻塞任务线程的执行
termination.signalAll();
}
return;
}
} finally {
mainLock.unlock();
}
// else retry on failed CAS
}
}
/**
* 方法在执行程序终止时调用。默认的实现什么都不做。
* 注意:正确嵌套多个重写,子类通常应该调用 {@code超级。在这个方法中终止}。
*/
protected void terminated() { }
6、内部类Worker
Worker 主要用来维护正在运行中的线程的中断状态,worker可以被看作是一个执行器
AbstractQueuedSynchronizer,以简化获取和释放围绕每个任务执行的锁。这可以防止那
些旨在唤醒等待任务的工作线程而不是中断正在运行的任务的中断。我们实现了一个简单
的不可重入互斥锁,而不是使用ReentrantLock,因为我们不希望工作任务在调用
ScheduledExecutorService这样的池控制方法时能够重新获得锁。
一个工作器表示线程池中一个工作线程,一个工作线程可能会执行多个任务。
Worker 定义如下:
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable
{
/**
*
*/
private static final long serialVersionUID = 6138294804551838833L;
//线程,表示线程池中的工作线程。如果工厂失败,则为空。
final Thread thread;
//thread线程的第一个任务
Runnable firstTask;
//线程任务计数器,统计每个线程完成的任务数,即task 个数
volatile long completedTasks;
/**
* 在Worker 构造函数中创建线程
*/
Worker(Runnable firstTask) {
//初始化同步状态值
setState(-1); // 禁止中断,直到runWorker
this.firstTask = firstTask;
/**
* 以当前worker对象构建一个新的线程,用来执行firstTask
* 在ThreadFactory 中可以对线程池中的线程做些处理,如设置线程名称,可以参考 DefaultThreadFactory 类的实现
*/
this.thread = getThreadFactory().newThread(this);
}
/** */
public void run() {
//将当前worker委托给外部的 runWorker() 方法执行
//todo 核心方法
runWorker(this);
}
protected boolean isHeldExclusively() {
return getState() != 0;
}
//当前线程显式的获取锁,0:没有持有锁,1:持有锁
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) {
}
}
}
}
1784

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



