ThreadPoolExecutor线程池源码剖析
ThreadPoolExecutor源码剖析
自定义构建线程池,可以细粒度的控制线程池,去管理内存的属性,并且针对一些参数的设置可能更好的在后期排查问题。这也是阿里巴巴开发手册推荐我们这样做的。
先看一下ThreadPoolExecutor提供的七个核心参数
public ThreadPoolExecutor(int corePoolSize, // 核心工作线程(当前任务执行结束后,不会被销毁)
int maximumPoolSize, // 非核心工作线程(最大工作线程)(代表当前线程池中,一共可以有多少个工作线程)
long keepAliveTime,// 非核心工作线程的存活时间,说白了就是,当阻塞队列中没有任务的时候,再等待多长时间就销毁了。
TimeUnit unit,// 非核心工作线程的存活时间的单位
BlockingQueue<Runnable> workQueue,// 任务在没有核心工作线程处理时,任务先扔到阻塞队列中
ThreadFactory threadFactory,// 构建线程的线程工厂,可以设置thread的一些信息
RejectedExecutionHandler handler) { // 当线程池无法处理投递过来的任务时,执行当前的拒绝策略
// 初始化线程池的操作,省略...
}
ThreadPoolExecutor常见属性讲解:
// ctl高3位表示线程池状态,低29位表示工作线程的个数
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
// 声明了一个常量:COUNT_BITS = 29
private static final int COUNT_BITS = Integer.SIZE - 3;
// CAPACITY就是当前工作线程能记录的工作线程的最大个数
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
// 线程池状态
// runState is stored in the high-order bits
// 111:代表RUNNING状态,RUNNING可以处理任务,并且处理阻塞队列中的任务
private static final int RUNNING = -1 << COUNT_BITS;
// 000:代表SHUTDOWN状态,不会接收新任务,正在处理的任务正常进行,阻塞队列的任务也会做完。
private static final int SHUTDOWN = 0 << COUNT_BITS;
// 001:代表STOP状态,不会接收新任务,正在处理任务的线程会被中断,阻塞队列的任务一个不管。
private static final int STOP = 1 << COUNT_BITS;
// 010:代表TIDYING状态,这个状态是由SHUTDOWN或者STOP转换过来的,代表当前线程池马上关闭,就是过渡状态
private static final int TIDYING = 2 << COUNT_BITS;
// 011:代表TERMINATED状态,这个状态是TIDYING状态转换过来的,转换过来只需要执行一个terminated方法。
private static final int TERMINATED = 3 << COUNT_BITS;
// Packing and unpacking ctl
// 基于&运算的特点,保证只会拿到ctl高三位的值
private static int runStateOf(int c) { return c & ~CAPACITY; }
// 基于&运算的特点,保证只会拿到ctl低29位的值。
private static int workerCountOf(int c) { return c & CAPACITY; }
// 通过该值,能够执行线程池状态和线程数量
private static int ctlOf(int rs, int wc) { return rs | wc; }
线程池状态的特点以及转换方式:
execute源码的分析
public void execute(Runnable command) {
// 提交过来的任务不能为null
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的值,(前三位代表线程池状态+后29位代表线程数量)
int c = ctl.get();
// 如果工作线程数<核心线程数
if (workerCountOf(c) < corePoolSize) {
// 将任务添加到工作队列,如果添加成功,直接返回,
// 参数:true:核心线程,false:非核心线程
if (addWorker(command, true))
return;
// 如果添加失败,再重新获取一下线程池的状态和工作线程的数量
c = ctl.get();
}
// 运行到这里表示核心线程数已满
// 如果当前线程池为运行状态,则将任务添加到 任务队列中
// private final BlockingQueue<Runnable> workQueue;
if (isRunning(c) && workQueue.offer(command)) {
// 再重新获取一下线程池的状态和工作线程的数量
int recheck = ctl.get();
// 如果当前线程池不是运行状态,那么就将当前任务从队列中移除出去
if (! isRunning(recheck) && remove(command))
// 移除出去该任务之后,使用拒绝策略,拒绝当前任务,告诉对方,这个任务我不执行了,你看看该怎么弄是落库还是怎么滴
reject(command);
// 如果当前工作线程的个数为0,则该任务还需要执行,则添加到非核心线程中
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
// 将当前任务放到非核心线程中去处理
else if (!addWorker(command, false))
// 如果非核心线程处理不了就执行拒绝策略
reject(command);
}
总结一下:任务来了,先交由核心线程进行处理,如果核心线程处理不过来的话,就扔到队列中,如果队列中满了,则交由非核心线程进行处理,如果非核心线程也处理不过来了,则执行拒绝策略。当然这是线程池的默认执行步骤,由于这个方法没有被final进行修饰,我们是可以重写这个方法的,来修改线程池的执行步骤。
addWorker源码剖析:
// 核心线程和非核心线程的创建都是基于这个方法创建的。
private boolean addWorker(Runnable firstTask, boolean core) {
// 总结:这两个for循环说白了就是给ctl增加了一个线程的数量
retry: // 跳出双层for循环的一种方式
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
// 如果线程池状态不是RUNNING.直接return false。
// 说白了就是看看该线程池是否是不接受任务的状态
if (rs >= SHUTDOWN &&
// 第二个判断,解决在shutdown状态下,没有工作线程,要构建一个线程处理阻塞队列中任务的情况
! (rs == SHUTDOWN && firstTask == null && ! workQueue.isEmpty()))
return false;
// 说白了,以下是线程池状态是RUNNING的情况下才会执行的
for (;;) {
int wc = workerCountOf(c);
// 工作线程个数不能超过最大值
if (wc >= CAPACITY ||
// true:判断核心线程数 false:判断最大线程数(也就是非核心线程数)
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
// 走到这里,说明能够接受该线程任务,需要将ctl的低29位加1
// 说白了就是线程的数量+1
if (compareAndIncrementWorkerCount(c))
// 如果成功,跳出最外层循环。
break retry;
c = ctl.get(); // Re-read ctl
// 如果当前线程状态不一致了,从最外层retry再进来重新执行。
if (runStateOf(c) != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
// 如果当前线程状态保持一致,则只执行内层for循环就可以了
}
}
// 走到这里说明修改ctl的值成功加1了,那么接下来就要执行该任务了
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
w = new Worker(firstTask); // 创建工作线程并将任务封装到worker对象中
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
// 先上锁,因为hashset是线程不安全的
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();
// 将worker对象放到hashset集合中
workers.add(w);
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;
}
} finally {
mainLock.unlock();
}
if (workerAdded) {
// 调用Thread的start方法启动线程执行任务
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable
{
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker,抑制中断,直到runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
public void run() {
runWorker(this);
}
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
/*
w.unlock()底层是aqs的释放锁逻辑
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
*/
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
// 如果是核心任务就执行执行,如果没有核心任务,就从队列里面拿一个执行。具体可以点进getTask源码进行查看
while (task != null || (task = getTask()) != null) {
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();
} 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);
}
}
}
线程状态:
关闭线程池源码剖析:
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
advanceRunState(SHUTDOWN);
// 终止闲置的worker线程
interruptIdleWorkers();
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
tryTerminate();
}
public List<Runnable> shutdownNow() {
List<Runnable> tasks;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
advanceRunState(STOP);
// 终止所有worker线程
interruptWorkers();
tasks = drainQueue();
} finally {
mainLock.unlock();
}
tryTerminate();
return tasks;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
2021-08-31 适配器模式