- execute源码
public void execute(Runnable command) {
// 任务的具体实现逻辑类不能为空
if (command == null)
throw new NullPointerException();
/*
* 1 如果当前线程池中的线程数小于核心线程数corePoolSize,则创建一个新的线程,不过该线程是封装在Worker对象中
* 2 addWorker方法中的第一个参数是该线程的第一个任务,而第二个参数就是代表是否创建的是核心线程
* 3 如果当前线程池中的线程数已经满足了核心线程数corePoolSize,那么就会通过workQueue.offer()方法将任务添加到阻塞队列中等待执行
* 4 如果线程数已经达到了corePoolSize且阻塞队列中无法插入该任务(比如已满),并且没有超过最大线程数maximumPoolSize,那么线程池就会再增加一个非核心线程来执行该任务
* 5 如果确实已经达到了最大线程数,那么就拒绝这个任务
* */
int c = ctl.get();
// 检查当前线程数是否达到了核心线程数
if (workerCountOf(c) < corePoolSize) {
// 未达到核心线程数,则创建新核心线程
// 并将传入的任务作为该线程的第一个任务
if (addWorker(command, true))
// 添加核心线程成功则直接返回,如果没有添加成功,就该执行上面所说的3
return;
// 因为前面调用了耗时操作addWorker方法
// 所以线程池状态有可能发生了改变,重新获取状态等信息
c = ctl.get();
}
// 走到这里说明当前线程池中的线程数已经满足了核心线程数corePoolSize
// 如果线程池当前状态是运行中就调用workQueue.offer方法将任务放入阻塞队列
if (isRunning(c) && workQueue.offer(command)) {
// 因为这个放入操作比较耗时,所以在放入成功之后,又做了一些列的校验操作
int recheck = ctl.get();
// 如果当前状态变成了非运行中(因为线程池的状态只能从小到大进行状态迁移,如果不是RUNNING那么肯定是至少处于SHUTDOWN状态,从该状态开始就不再接收新任务了),则将刚才放入阻塞队列的任务拿出,拿出成功后,直接拒绝这个任务
// 疑问1
if (! isRunning(recheck) && remove(command))
reject(command);
// 如果线程池中没有线程了,那就创建一个非核心线程
// 这里没有看明白,一个线程也没有了,为什么创建的不是核心线程????
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
// 如果如果放入阻塞队列失败(如队列已满),则添加一个非核心线程
// 如果不是RUNNING 这里为什么还能新建线程呢?而疑问1的地方不是运行态为什么要取出来拒绝,而不是跟这里一样建一个非核心线程进行处理???
// 目测只能是addWorker逻辑中有非运行态的判断肯定也会创建不成功(具体可以查看addWorker源码注释)
else if (!addWorker(command, false))
// 如果添加线程失败(如已经达到了最大线程数),则拒绝任务
reject(command);
}
- addWorker源码
// 改方法的主要作用是新建一个线程并启用,创建的线程被包装成了Worker对象
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// 1 rs > SHUTDOWN 此时不再接受新的任务,直接返回添加失败
// 2 rs = SHUTDOWN:firtTask != null 也会创建线程失败(这里也正好印证了我们在execute函数注解中留下的疑问),此时不再接受任务,但是仍然会执行队列中的任务
// 3 线程池SHUTDOWN了不再接受新任务,但是此时队列不为空,那么还得创建线程把任务给执行完才行
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
/*
* 走都这里,说明线程池状态或者为RUNNING,
* 或者是SHUTDOWN状态,但是任务队列中还有任务,这个时候也是需要新建线程(当然这个线程究竟能不能新建成功,还需要后续一系列条件的限制)去执行完任务
* */
for (;;) {
int wc = workerCountOf(c);
/*
* 线程数不能超过容量限制;如果是创建核心线程,也不能超过核心线程数,非核心线程也不能超过设置的最大值
* */
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
// 原子的把线程数+1,这里只是把线程数+1,但是还没有真正的创建工作线程
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
}
}
// 走到这里就是真正的开始创建工作线程了
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
// 利用Worker构造方法中的线程池工厂创建线程,并把线程封装成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.
int rs = runStateOf(ctl.get());
/*
* 如果线程池没有关闭,或者 已经关闭且任务不为空
* */
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
// 检查线程是否仍然存活其实就是检查线程是否已启动(线程启动了就是存活了)
// 正常逻辑这里线程应该不是启动状态,只有在调用了start之后才是启动状态
// 所以如果这里是alive就报错
if (t.isAlive())
throw new IllegalThreadStateException();
workers.add(w); //添加到workers线程数组中
int s = workers.size();
// 整个线程池运行期间的最大并发线程数更新
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;
}
} finally {
mainLock.unlock();
}
// 添加到线程数组成功后,才启动新添加的线程
if (workerAdded) {
// 启动线程的方法是调用Thread类的start()方法,该方法会在内部调用Runnable接口的run()方法,即会调用Worker对象中的run方法,
// 这是因为 w = new Worker(firstTask)时 其中的newThread时把this(即Worker本身传进去了)而worker实现了Runnable接口
// 所以执行start就是执行run就是执行Worker对象的runWorker(this)方法
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
// 启动失败就回退线程的创建,即释放掉线程
addWorkerFailed(w);
}
return workerStarted;
}
我们知道一个Thread在执行完其中的run方法之后就会退出,线程的生命周期也就结束了,那线程池中的线程是如何做到复用的呢?我们来看以下Worker
类中的runWorker(this)方法。该方法会在线程启动时被调用(具体调用逻辑请看addWorker的源码注释)
- runWorker(this)源码分析
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
//在构造Worker对象的时候,会把一个任务添加进Worker对象中作为新增线程的第一个任务来执行
Runnable task = w.firstTask;
//已经将该任务拿出来进行执行,则需要将该worker对象 即线程池中的线程对象持有的任务清空
w.firstTask = null;
//将AQS锁资源的状态有-1变成0,运行该线程允许进行中断
w.unlock(); // allow interrupts
//用来判断执行任务的过程中,是否出现了异常,默认是异常退出
boolean completedAbruptly = true;
try {
// 这里先大概说一下getTask的大概逻辑,核心线程会一直阻塞等待任务队列中有任务
// 非核心线程会在等待keepAliveTime的超时时间之后,如果任务队列中还没有任务就会获取到null
// 然后退出whie循环,进入到finally中 执行processWorkerExit结束调线程
while (task != null || (task = getTask()) != null) {
//给该线程加锁,一个线程只处理一个任务
w.lock();
// 线程池是否是STOP状态
// 如果是,则确保当前线程是中断状态
// 如果不是,则确保当前线程不是 中断状态
// 中断对正在运行的线程不起作用,只对阻塞的线程起作用,这里具体怎么用??????
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
//扩展使用,在执行任务的run方法之前执行;前置钩子
beforeExecute(wt, task);
Throwable thrown = null;
try {
// 执行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();
}
}
// 正常执行完任务
completedAbruptly = false;
} finally {
//所有的任务都处理完后,或者执行任务的过程中出现了异常
processWorkerExit(w, completedAbruptly);
}
}
- getTask()源码
核心线程池可以复用的原理就在这个函数里面
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.
/*
* 如果线程池的当前状态为>=关闭的状态 并且 (已停止或者任务队列中为空)
* */
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount(); //Worker总数减1,返回null 外层的runWorker就会退出循环,进入销毁线程的逻辑
return null;
}
int wc = workerCountOf(c);
// Are workers subject to culling?
// allowCoreThreadTimeOut:是否允许core Thread超时,默认false
// workerCount是否大于核心核心线程池
// 该标志的含义是:是否需要等待keepAliveTime时间再去队列中获取
// 也就是说如果队列中没有任务,可以等待keepAliveTime时长,如果还没有任务的话,那么则返回null
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
// 如果设置了allowCoreThreadTimeOut,那么大于coreThread(核心线程)就会有会有超时时间(即keepAliveTime)的限制,
// 即如果当前的WorkerCount大于corePoolSize的话,那么超过的这些线程都会有超时的限制
//1如果线程数超过最大限制,直接线程数-1,然后返回null(该线程就会销毁)
//2如果启用了非核心线程超时设置,那么当获取任务超时并且线程池中有多于1个线程,就返回null并回收此线程
//3如果启用了非核心线程超时设置,那么当获取任务超时 并且任务队列为空,就减1个线程(如果只有一个线程就会减失败)
// 仍热会继续该循环,也就是说线程池中始终会至少有一个线程
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
// 如果启用了非核心线程超时设置,就使用poll获取任务,如果队列中没任务,该方法会获取超时,就会在下次循环中返回null
// 核心线程会使用take方法获取任务,take方法在任务队列中没有任务时,会阻塞。
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
//判断任务不为空返回任务
return r;
//获取一段时间没有获取到,获取超时
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}