reject(command);
//若线程数为0则启动一个空线程从workQueue中取任务
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
//不是running或者任务加入阻塞队列失败(阻塞队列满了)
//3、判断maximumPoolSize,阻塞队列已满且小于maximumPoolSize,创建新的worker
else if (!addWorker(command, false))
//4、大于等于maximumPoolSize,拒绝策略
reject(command);
}
当线程数大于等于corePoolSize
,任务被加入workQueue
时,对线程池的状态进行了double check
,这是有必要的:
-
在将任务加入
workQueue
前判断线程池是否是RUNNING
,不是则不加入workQueue
。 -
任务加入
workQueue
后还需要再判断一次线程池的状态是否是RUNNING
,因为在这个过程中可能线程池死亡或者外部调用了shundown()
或者shutdownNow()
使得线程池正在销毁,此时需要删除刚加入工作队列的任务,并触发拒绝策略。
当任务加入workQueue
后判断此时工作线程数为0,则启动一个空工作线程消费workQueue
中的任务。
execute()
的核心在addWorker(Runnable firstTask, boolean core)
,它是如何创建并启动一个工作线程的呢?addWorker
第二个参数为true时线程数与corePoolSize
比较,false时线程数与maximumPoolSize
比较。
addWorker
代码很长,有两个大的for循环,逻辑主要涉及2步:
-
第一个for循环:自旋CAS操作
workerCount
加1。 -
第二个for循环:创建并启动新Worker线程。
在worderCount
加1和创建worker时都反复判断线程池当前的运行状态,是为了当线程池调用了shutdown()
或者shutdownNow()
时做出相应的措施。
private boolean addWorker(Runnable firstTask, boolean core) {
//1、这个循环主要是为了自旋 cas workerCount+1,成功之后就创建worder
// 因为代码块没有加锁,且是有可能多个线程同时操作,所以采用了cas乐观锁的方式。
retry:
for (;😉 {
int c = ctl.get();
int rs = runStateOf©;
// Check if queue empty only if necessary.
//线程池状态 大于等于SHUTDOWN(不是running),且非(SHUTDOWN 且task为null且阻塞队列不为空)
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;😉 {
int wc = workerCountOf©;
//worker数>=CAPACITY 或者worker数>=corePoolSize or maximumPoolSize 直接返回false
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
//cas workercount+1
if (compareAndIncrementWorkerCount©)
break retry;
c = ctl.get(); // Re-read ctl
if (runStateOf© != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}
//2、创建worker
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
//1、new Worker
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
//1.1、这里需要加锁
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
//当获取锁后再次检查 线程池状态
int rs = runStateOf(ctl.get());
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
//工作线程已经是startable
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
//2、工作线程还未启动,加入workers(HashSet)
workers.add(w);
int s = workers.size();
if (s > largestPoolSize)
//2.2、实时修改largestPoolSize = s
largestPoolSize = s;
workerAdded = true;
}
} finally {
mainLock.unlock();
}
if (workerAdded) {
//启动工作线程
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
//worder线程启动失败后的一些措施
//1、从workers删除worder
//2、worderCount递减
//3、尝试终止线程池
addWorkerFailed(w);
}
return workerStarted;
}
第一个for循环,workerCount
自旋CAS加1的过程中判断线程数是否满足corePoolSize
或者maximumPoolSize
,workerCount
加1成功结束外围循环,也有可能在CAS的过程中workerCount
改变导致失败则重新判断、自旋重试。
第二个for循环,创建Worker
工作线程,并启动,启动的过程中需要加锁,因为启动完Worker,还需要将其加入到workers
中,并将workers.size()
赋值给largestPoolSize
;如果Worker
启动失败,则需要一些措施:
-
从
workers
删除Worder
。 -
worderCount
自旋CAS递减。 -
如果线程池正处于销毁的过程,则尝试自旋终止线程池。
private void addWorkerFailed(Worker w) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
if (w != null)
//1、从workers删除worder
workers.remove(w);
//2、worderCount cas自旋递减
decrementWorkerCount();
//3、如果线程池正处于销毁的过程,则尝试自旋终止线程池
tryTerminate();
} finally {
mainLock.unlock();
}
}
addWorker
中创建的工作线程是Worker
对象,它是ThreadPoolExecutor
的内部类,继承于AbstractQueuedSynchronizer
,相当于是一把锁,实现了Runnable
接口,又是一个线程。
Worker
有两个核心的成员变量thread
和firstTask
。因为Worker
本身是一个Runnable
线程,初始化时会被ThreadFactory
包装创建为一个Thread
赋值给thread
,addWorker
方法中直接调用thread.start()
启动Worker
线程;firstTask
是提交进来的任务,Worker
直接调用firstTask
的run()函数,执行任务代码。
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable
{
//Worker是不可能被序列化的,但是为了禁止javac告警而提供serialVersionUID
private static final long serialVersionUID = 6138294804551838833L;
//这个线程非常的重要 Worker就是运行在其中的
final Thread thread;
//任务线程,并不会当做线程去start而是直接调用run()
Runnable firstTask;
//数据统计,可以忽略
volatile long completedTasks;
/**
- Creates with given first task and thread from ThreadFactory.
*/
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
//默认ThreadFactory,创建工作线程
this.thread = getThreadFactory().newThread(this);
}
}
1、runWorker执行任务
Worker
线程启动后会自动条用其run
函数:
当Worker
刚start时,直接拿Worker
的成员变量firstTask
来执行任务代码,当firstTask
为空时,从工作队列中循环取出task
执行,而工作队列为空则阻塞等待。
runWorker()
在代码中提供了两个空函数beforeExecute
和afterExecute
,一般称之为钩子函数,用户可以自行继承ThreadPoolExecutor
时,将其重写,加上一些业务逻辑。
public void run() {
runWorker(this);
}
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
while (task != null || (task = getTask()) != null) {
w.lock();
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
//这里是一个空函数,使用者可以自行继承ThreadPoolExecutor 并重写beforeExecute
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 {
//这也是一个空函数,使用者可以自行继承ThreadPoolExecutor 并重写afterExecute
afterExecute(task, thrown);
}
小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
总结
虽然我个人也经常自嘲,十年之后要去成为外卖专员,但实际上依靠自身的努力,是能够减少三十五岁之后的焦虑的,毕竟好的架构师并不多。
架构师,是我们大部分技术人的职业目标,一名好的架构师来源于机遇(公司)、个人努力(吃得苦、肯钻研)、天分(真的热爱)的三者协作的结果,实践+机遇+努力才能助你成为优秀的架构师。
如果你也想成为一名好的架构师,那或许这份Java成长笔记你需要阅读阅读,希望能够对你的职业发展有所帮助。
[外链图片转存中…(img-b9CpaWFw-1711087210715)]
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
[外链图片转存中…(img-iFJgGKRd-1711087210716)]
总结
虽然我个人也经常自嘲,十年之后要去成为外卖专员,但实际上依靠自身的努力,是能够减少三十五岁之后的焦虑的,毕竟好的架构师并不多。
架构师,是我们大部分技术人的职业目标,一名好的架构师来源于机遇(公司)、个人努力(吃得苦、肯钻研)、天分(真的热爱)的三者协作的结果,实践+机遇+努力才能助你成为优秀的架构师。
如果你也想成为一名好的架构师,那或许这份Java成长笔记你需要阅读阅读,希望能够对你的职业发展有所帮助。
[外链图片转存中…(img-qCwo3mN1-1711087210717)]