并发编程之创建核心线程逻辑分析
小伙伴们,大家好!!!上一节咱们一起了解了线程池的由来(掌握线程池的基本知识,入坑线程池),上一篇主要是代码层面作了简要分析,我觉得阅读起来可能不是特别的方便,故此篇想以图的形式对线程池的运行原理进行补充以及对创建核心线程的核心代码分析。
文章目录
1、线程池创建线程代码执行逻辑分析
- 如下图所示:
1.1 模拟银行工作场景展开对线程池的分析
模拟银行办理业务是现实生活中不错的应用案例,非常贴近我们的生活,可以更好的加深我们理解。
2、创建线程分析(ThreadPoolExecutor#addWorker)
2.1 方法参数解析
/**
* @param: firstTask 创建执行的线程
* @param: core 为true时表示创建核心线程,fasle表示创建非核心线程
*/
private boolean addWorker(Runnable firstTask, boolean core)
2.2 demo案例促进对continue和break标签的理解
- 运行代码
/**
* @author Mr.Gao
* @date 2023/12/18 9:57
* @apiNote:
*/
public class TestTip {
public static void main(String[] args) {
Integer skipLoopNum = skipLoop();
System.out.println(skipLoopNum);
}
/**
* 循环对比break和continue的区别?
*
* @return
*/
public static Integer skipLoop() {
ThreadLocalRandom current = ThreadLocalRandom.current();
int num = 0;
Integer receiveRandomNum = null;
retry:
for (; ; ) {
System.out.println("@@@@@#####~~~~~");
for (; ; ) {
num++;
// 随机生成数
int randomNum = current.nextInt(0, 10);
System.out.println();
if (0 == randomNum) {
System.out.println("随机数等于0,执行Break操作!");
receiveRandomNum = randomNum;
break retry;
}
if (6 == randomNum) {
System.out.println("随机数等于6,执行continue操作!");
receiveRandomNum = randomNum;
continue retry;
}
}
}
System.out.println("执行了,num=" + num + "次");
return receiveRandomNum;
}
}
- 运行结果
- 结论
上述Demo案例理解起来也是非常的简单,此处有用到
循环标志(类似于设置一个flag标志位,处于循环中时,当执行了break或continue时跳转至标志位)
,按照商户运行结果我们可以看到,continue
是跳出本次循环且本身仍处于循环之中,break
是跳出本次循环并跳转至标志位(跳转至标志位之后退出循环
)。
故此,验证了continue是跳出本次循环且执行下一次循环,而break是终止循环跳出!!!
2.3 addWorker方法解析
上述
2.2目的是用来巩固break和continue的理解
,进而方便解读下述源码部分
private boolean addWorker(Runnable firstTask, boolean core) {
retry: // 设定一个标志位,用于跳出循环
for (;;) {
int c = ctl.get();
// 获取线程池的运行状态
int rs = runStateOf(c);
// Check if queue empty only if necessary.
// 线程池非关闭状态 且 新创建任务不等于Null 且 工作任务队列为空时 返回false
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) {
// 工作线程数
int wc = workerCountOf(c);
// 若core为true时,比较的是核心线程大小
// 若为false时,比较的是最大线程池大小
// 当工作线程数 大于 (核心线程数或最大线程数)时 返回false
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
// 此处进行CAS比较操作,如果 加1操作执行成功之后 则执行break操作 退出循环
if (compareAndIncrementWorkerCount(c))
break retry;
// 重新获取
c = ctl.get();
//由于workerCount执行CAS更改失败 重试内循环
if (runStateOf(c) != rs)
continue retry;
}
}
/**
* workerStarted : 用来标识工作线程是否被启动
* workerAdded : 用来表示工作线程是否创建成功
*/
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
/**
* 创建一个工作线程 worker,Worker实现了Runnable接口
*
*/
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
// 通过ReentrantLock 的 lock方法进行加锁
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());
// 线程池关闭且firstTask为Null时 或 线程池状态为运行状态时
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
// 若线程t状态为存活时,抛出 IllegalThreadStateException异常
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
// 将创建好的worker添加至workers中
workers.add(w);
int s = workers.size();
// 若workers大小大于最大线程池大小时,最大线程池大小即等于workers大小
if (s > largestPoolSize)
largestPoolSize = s;
// true表示添加成功
workerAdded = true;
}
} finally {
// 释放锁
mainLock.unlock();
}
if (workerAdded) {
// 若worker添加成功后 启动线程
t.start();
workerStarted = true;
}
}
} finally {
// 若线程启动失败,则执行以下逻辑:
// 1、调用workers的remove方法
// 2、workerCount数减1
// 3、tryTerminate 尝试终止
if (! workerStarted)
addWorkerFailed(w);
}
// 返回结果
return workerStarted;
}
2.4 解析Worker对象
Worker对象
实现Runnable接口
且继承AbstractQueuedSynchronizer(简称:AQS
)
- 执行Worker的run方法,实际执行的是runWorker方法
2.4.1 Worker的runWorker方法
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
// 如果task不为空 或 从workQueue获取一个task不为空时 先执行lock方法
while (task != null || (task = getTask()) != null) {
w.lock();
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt(); // 线程中断
try {
// 此方法不做任何事情,用于子类自定义扩展实现
beforeExecute(wt, task);
Throwable thrown = null;
try {
// 执行Runnable接口的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;//将task置为null
w.completedTasks++;//任务完成数加1
w.unlock();// 释放锁资源
}
}
completedAbruptly = false;
} finally {
// 处理worker退出,执行以下逻辑:
// 1、workers移除当前worker
// 2、tryTerminate尝试终止
processWorkerExit(w, completedAbruptly);
}
}
2.4.2 Worker的getTask方法
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
for (;;) {
int c = ctl.get();
// 获取线程池运行状态
int rs = runStateOf(c);
// 若线程池状态为SHUTDOWN且STOP 或 工作队列为空时 返回为null
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
// 表示工作队列不为空或线程池处于运行状态 ,wc为当前获取的工作线程数
int wc = workerCountOf(c);
// allowCoreThreadTimeOut 默认为false 或 工作线程数大于核心线程数 timed 为true
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
// 如果工作线程数大于最大线程池大小
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
// 从workQueue队列头中获取一个Runnable实例
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;// 返回待处理的任务线程
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
3、小结
经过上述分析以及结合我们的生活日常充分让我们了解到线程池中的工作原理,并且重新回顾了break和contiue标签,在本篇中唯一比较生疏的一点就是
AbstractQueuedSynchronizer即就是我们常说的AQS
,接下来我会以AQS为主,让我们一起继续学习并发编程中的知识点。
最后,非常感谢能看到此处的小伙伴们,你们的每一个点赞与关注都会激发我的战斗力,各位道友希望咱们互相监督,互相学习。如存在错误的地方望各位道友及时指正,非常感谢!!!