一、从构造方法开始

二、exucute()
scss
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.
*/
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get(); //如果创建线程失败,会进入这里重读状态
}
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);
}
- RUNNING: -1 << COUNT_BITS,即高3位为111,该状态的线程池会接收新任务,并处理阻塞队列中的任务;
- SHUTDOWN: 0 << COUNT_BITS,即高3位为000,该状态的线程池不会接收新任务,但会处理阻塞队列中的任务;
- STOP : 1 << COUNT_BITS,即高3位为001,该状态的线程不会接收新任务,也不会处理阻塞队列中的任务,而且会中断正在运行的任务;
- TIDYING : 2 << COUNT_BITS,即高3位为010, 所有的任务都已经终止;
- TERMINATED: 3 << COUNT_BITS,即高3位为011, terminated()方法已经执行完成
ctl中储存了线程池的状态和线程数,低29位储存线程数量,高3位储存线程状态。初始时,低三位为RUNNING,线程数是0。当需要获取线程池信息时,通过按位与运算(&)即可取出状态或线程数量,这里的ctl.get()实际上是先获取了线程池32位信息。
workerCountOf(c)方法即为从ctl中取出线程的数量

如果当前线程数量小于线程池核心数,进入addWorker(),参数core为true时线程池数量最大即为corePoolSize,这里超过不会创建新线程(救急线程)
三、addWorker()
ini
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c); //获取运行状态
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN && //无任务或运行状态为非SHUTDOWN的结束态时返回false,如果在SHUTDOWN状态且仍有任务会执行完剩余任务
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) {
int wc = workerCountOf(c); //获取线程数量
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize)) //core为true时大于corePoolSize即不再创建新线程,无救济线程
return false;
if (compareAndIncrementWorkerCount(c)) //如果满足创建新线程条件则线程池数量先加1
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 {
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)) { //再次检查运行状态
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
workers.add(w); //将线程加入工作集合,这是一个HashSet
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s; //记录最大线程池中线程数,可用于观测线程池运行情况
workerAdded = true; //加入成功的标识
}
} finally {
mainLock.unlock();
}
if (workerAdded) { //如果添加成功,start线程
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w); //如果线程启动失败,这里会从workers中移除添加的worker,并且尝试终止线程池
}
return workerStarted; //返回值即可看作线程是否创建、添加、启动全部成功
}
```
概括的说,addWorker()主要做了线程池当前状态适不适合创建线程,如果适合则加入workers并启动线程执行任务。
四、excute() 第二部分
scss
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.
*/
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get(); //如果创建线程失败,会进入这里重读状态
}
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);
}
如果此时工作线程全部正在工作,又有一个新的excute()请求进入,任务将加入workQueue等待其他线程空闲后执行,并不会直接创建应急线程([coreSize,maximumPoolSize]间的线程)。
调试代码
csharp
public class threadPool {
public static void main(String[] args) {
/* ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);
for(int i = 0 ;i < 5 ; i ++){
fixedThreadPool.execute(new WorkerRunnable(i));
}
fixedThreadPool.shutdown();*/
ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 4, 60L,
TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
for(int i = 0;i < 5;i++){
if(i == 2){
executor.execute(new WorkerRunnable(i));
}
executor.execute(new WorkerRunnable(i));
}
}
}
class WorkerRunnable implements Runnable{
private Integer num;
WorkerRunnable(Integer num){
this.num = num;
}
@Override
public void run() {
System.out.println("executing...");
System.out.println("线程: " + Thread.currentThread() + " 正在执行任务");
try {
Thread.sleep(1000000000L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("ending...");
}
}
线程2并没有被创建,只是任务加入了workQueue
应急线程创建时机
scss
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);
结合源码分析,如果给定的是一个有界阻塞队列,当任务不断放入阻塞队列导致阻塞队列爆满,workQueue.offer()放入任务失败,返回false,进入最后一个else if断,在else if中addWorker()的参数core=false,意味着可以创建救急线程了(迷糊了再看一下addWorker的源码分析)。
五、工作线程如何获取并执行阻塞队列中的任务
首先找到入口,该内部类实现了Runnable方法,线程start后先来这里。

csharp
public void run() { //入口
runWorker(this);
}
接下来进入runWorker方法
java
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask; //这里获取的是第一次创建线程时分配的任务 (有点绕,看看excute()),先将它临时储存到task
w.firstTask = null; //设为null,为后续循环获取新的任务做准备
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
while (task != null || (task = getTask()) != null) { //如果初始任务还没执行,先进入循环块执行初始任务。如果执行过了,则循环调用getTask()方法
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
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(); //真正执行任务的入口(自定义的Runnable)
} 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; //task设为空,保证循环获取方法
w.completedTasks++; //记录已经执行的数量
w.unlock(); //解锁
}
}
completedAbruptly = false; //没被打断标记
} finally {
processWorkerExit(w, completedAbruptly); //如果被打断了会把线程数量减到0
}
}
这里比较简单,getTask()是线程循环获取阻塞队列方法的实现,包括KeepAlive的具体实现,getTask()才是正菜。
ini
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())) { //如果线程池状态为SHUTDOWN且任务队列为空,或线程池将关闭且不处理新任务
decrementWorkerCount(); //已经是关闭状态 线程数量 减 到 0
return null;
}
int wc = workerCountOf(c); //获取线程数量
// Are workers subject to culling?
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize; //有救急线程时 timed为true
if ((wc > maximumPoolSize || (timed && timedOut)) //执行超时(timed == true),说明有救急线程在运行
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c)) //这里大概是想销毁救急线程?
return null;
continue;
}
try {
Runnable r = timed ?//有救急线程,timed为true,则任务执行有最大时间,执行超时返回null
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : //救急线程尝试拉取任务,如果count == 0(任务数量为0),超过等待时间后没有拿到任务则返回null,即救急线程闲了 keepAlive 秒
workQueue.take(); //无救急线程时调用,直接返回
if (r != null)
return r; //执行成功则直接return
timedOut = true; //超时,没拿到任务,救急线程太闲了该死了
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
六、shutdown()
scss
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
advanceRunState(SHUTDOWN);
interruptIdleWorkers();
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
tryTerminate();
}
java
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();
}
}
这里会打断每个线程,注意打断只是设置打断标记,runWorker()中执行完当前的作业重新循环才会感知到打断标记为true。
scss
final void tryTerminate() {
for (;;) {
int c = ctl.get();
if (isRunning(c) ||
runStateAtLeast(c, TIDYING) ||
(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
return;
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
}
}
尝试真正结束线程池
七、总结
执行逻辑: 程序员先创建线程池,初始状态下线程池中并没有线程。调用execute()方法后,创建Worker对象封装新的线程和初始任务(firstTask)并start线程,start后进入Worker实现的Runnable方法中,然后进入runWorker()中执行初始任务,执行完初始任务后循环调用getTask();
当调用execute()方法阻塞队列未满,最大核心线程数已满时,任务会放入阻塞队列,等待getTask()方法获取任务;
当调用execute()方法后阻塞队列已满,开始创建救急线程,救急线程同样拥有初始任务(firstTask)和新的线程,执行逻辑和第一次调用execute()相同,除了execute在KeepAlive时间内获取不到新的任务时阻塞队列会返回null,然后会关闭救急线程。
自己的debug代码
java
package org.example.threadpool;
import java.util.concurrent.*;
/**
* ---code_explore---
*
* @author summer77
* @date 2024/1/17 14:14
* <p>
* ---threadPool---
*/
public class threadPool {
public static void main(String[] args) {
/* ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);
for(int i = 0 ;i < 5 ; i ++){
fixedThreadPool.execute(new WorkerRunnable(i));
}
fixedThreadPool.shutdown();*/
ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 3, 30L,
TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(1),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
for(int i = 0;i < 5;i++){
if(i == 3){
executor.execute(new WorkerRunnable(5,i));
}else if(i == 2){
executor.execute(new WorkerRunnable(40,i));
}
else {
executor.execute(new WorkerRunnable(10000000,i));
}
}
executor.shutdown();
}
}
class WorkerRunnable implements Runnable{
private Integer num;
private Integer i;
WorkerRunnable(Integer num,Integer i){
this.num = num;
this.i = i;
}
@Override
public void run() {
System.out.println(Thread.currentThread() + "executing...");
System.out.println("线程: " + Thread.currentThread() + " 正在执行任务" + i);
try {
Thread.sleep(num * 1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread() + "ending...");
}
}
第一次写文,有错求指正
