ThreadPoolExecutor应用源码剖析(四)

3.3.8 ThreadPoolExecutor的关闭方法

首先查看shutdownNow方法,可以从RUNNING状态转变为STOP

// shutDownNow方法,shutdownNow不会处理阻塞队列的任务,将任务全部给你返回了。
public List<Runnable> shutdownNow() {
// 声明返回结果
List<Runnable> tasks;
// 加锁
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 不关注这个方法……
checkShutdownAccess();
// 将线程池状态修改为STOP
advanceRunState(STOP);// 无论怎么,直接中断工作线程。
interruptWorkers();
// 将阻塞队列的任务全部扔到List集合中。
tasks = drainQueue();
} finally {
// 释放锁
mainLock.unlock();
}
tryTerminate();
return tasks;
}
// 将线程池状态修改为STOP
private void advanceRunState(int STOP) {
// 死循环。
for (;;) {
// 获取ctl属性的值
int c = ctl.get();
// 第一个判断:如果当前线程池状态已经大于等于STOP了,不管了,告辞。
if (runStateAtLeast(c, STOP) ||
// 基于CAS,将ctl从c修改为STOP状态,不修改工作线程个数,但是状态变为了STOP
// 如果修改成功结束
ctl.compareAndSet(c, ctlOf(STOP, workerCountOf(c))))
break;
}
}
// 无论怎么,直接中断工作线程。
private void interruptWorkers() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 遍历HashSet,拿到所有的工作线程,直接中断。
for (Worker w : workers)
w.interruptIfStarted();
} finally {
mainLock.unlock();
}
}
// 移除阻塞队列,内容全部扔到List集合中
private List<Runnable> drainQueue() {
BlockingQueue<Runnable> q = workQueue;
ArrayList<Runnable> taskList = new ArrayList<Runnable>();
// 阻塞队列自带的,直接清空阻塞队列,内容扔到List集合
q.drainTo(taskList);
// 为了避免任务丢失,重新判断,是否需要编辑阻塞队列,重新扔到List
if (!q.isEmpty()) {
for (Runnable r : q.toArray(new Runnable[0])) {
if (q.remove(r))
taskList.add(r);
}
}
return taskList;
}
// 查看当前线程池是否可以变为TERMINATED状态
final void tryTerminate() {
// 死循环。
for (;;) {
// 拿到ctl
int c = ctl.get();
// 如果是RUNNING,直接告辞。
// 如果状态已经大于等于TIDYING,马上就要凉凉,直接告辞。
// 如果状态是SHUTDOWN,但是阻塞队列还有任务,直接告辞。
if (isRunning(c) ||
runStateAtLeast(c, TIDYING) ||
(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
return;
// 如果还有工作线程
if (workerCountOf(c) != 0) {
// 再次中断工作线程
interruptIdleWorkers(ONLY_ONE);
// 告辞,等你工作线程全完事,我这再尝试进入到TERMINATED状态
return;
}
// 加锁,为了可以执行Condition的释放操作
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 将线程池状态修改为TIDYING状态,如果成功,继续往下走
if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {try {
// 这个方法是空的,如果你需要在线程池关闭后做一些额外操作,这里你可以自行实现
terminated();
} finally {
// 最终修改为TERMINATED状态
ctl.set(ctlOf(TERMINATED, 0));
// 线程池提供了一个方法,主线程在提交任务到线程池后,是可以继续做其他操作的。
// 咱们也可以让主线程提交任务后,等待线程池处理完毕,再做后续操作
// 这里线程池凉凉后,要唤醒哪些调用了awaitTermination方法的线程
termination.signalAll();
}
return;
}
} finally {
mainLock.unlock();
}
// else retry on failed CAS
}
}

再次shutdown方法,可以从RUNNING状态转变为SHUTDOWN
shutdown状态下,不会中断正在干活的线程,而且会处理阻塞队列中的任务

public void shutdown() {
// 加锁。。
final ReentrantLock mainLock = this.mainLock;mainLock.lock();
try {
// 不看。
checkShutdownAccess();
// 里面是一个死循环,将线程池状态修改为SHUTDOWN
advanceRunState(SHUTDOWN);
// 中断空闲线程
interruptIdleWorkers();
// 说了,这个是为了ScheduleThreadPoolExecutor准备的,不管
onShutdown();
} finally {
mainLock.unlock();
}
// 尝试结束线程
tryTerminate();
}
// 中断空闲线程
private void interruptIdleWorkers(boolean onlyOne) {
// 加锁
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers) {
Thread t = w.thread;
// 如果线程没有中断,那么就去获取Worker的锁,基于tryLock可知,不会中断正在干活的线程
if (!t.isInterrupted() && w.tryLock()) {try {
// 会中断空闲线程
t.interrupt();
} catch (SecurityException ignore) {
} finally {
w.unlock();
}
}
if (onlyOne)
break;
}
} finally {
mainLock.unlock();
}
}

3.4 线程池的核心参数设计规则

线程池的使用难度不大,难度在于线程池的参数并不好配置。
主要难点在于任务类型无法控制,比如任务有CPU密集型,还有IO密集型,甚至还有混合型的。
因为IO咱们无法直接控制,所以很多时间按照一些书上提供的一些方法,是无法解决问题的。
《Java并发编程实践》
想调试出一个符合当前任务情况的核心参数,最好的方式就是测试。
需要将项目部署到测试环境或者是沙箱环境中,结果各种压测得到一个相对符合的参数。
如果每次修改项目都需要重新部署,成本太高了。
此时咱们可以实现一个动态监控以及修改线程池的方案。
因为线程池的核心参数无非就是:
● corePoolSize:核心线程数
● maximumPoolSize:最大线程数
● workQueue:工作队列
线程池中提供了获取核心信息的get方法,同时也提供了动态修改核心属性的set方法。
[image]
也可以采用一些开源项目提供的方式去做监控和修改
比如hippo4j就可以对线程池进行监控,而且可以和SpringBoot整合。
Github地址:https://github.com/opengoofy/hippo4j
官方文档:https://hippo4j.cn/docs/user_docs/intro

3.5 线程池处理任务的核心流程

基于addWorker添加工作线程的流程切入到整体处理任务的位置

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/201070.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode双指针:第一个错误的版本

LeetCode双指针&#xff1a;第一个错误的版本 题目描述 你是产品经理&#xff0c;目前正在带领一个团队开发新的产品。不幸的是&#xff0c;你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的&#xff0c;所以错误的版本之后的所有版本都是错的。 …

2023年【危险化学品经营单位主要负责人】及危险化学品经营单位主要负责人模拟考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 危险化学品经营单位主要负责人根据新危险化学品经营单位主要负责人考试大纲要求&#xff0c;安全生产模拟考试一点通将危险化学品经营单位主要负责人模拟考试试题进行汇编&#xff0c;组成一套危险化学品经营单位主要…

深度优先搜索(DFS)LeetCode 2477. 到达首都的最少油耗

2477. 到达首都的最少油耗 给你一棵 n 个节点的树&#xff08;一个无向、连通、无环图&#xff09;&#xff0c;每个节点表示一个城市&#xff0c;编号从 0 到 n - 1 &#xff0c;且恰好有 n - 1 条路。0 是首都。给你一个二维整数数组 roads &#xff0c;其中 roads[i] [ai,…

(十四)Flask之闪现flash

闪现—flash 这可不是LOL或是王者荣耀里的闪现哦~ Flask 中的 “闪现”&#xff08;flash&#xff09;是一种在请求之间传递消息的机制。它允许你将一条消息保存在一个请求中&#xff0c;在下一个请求中获取并显示该消息&#xff0c;然后立即将其删除【设置完之后阅后即焚&am…

Day14——数据结构和集合源码

1.数据结构 简单来说&#xff0c;数据结构&#xff0c;就是一种程序设计优化的方法论&#xff0c;研究数据的逻辑结构和物理结构以及它们之间相互关系&#xff0c;并对这种结构定义相应的运算&#xff0c;目的是加快程序的执行速度、减少内存占用的空间。 1.1 数据的逻辑结构…

小航助学题库白名单竞赛考级蓝桥杯等考scratch(12级)(含题库教师学生账号)

需要在线模拟训练的题库账号请点击 小航助学编程在线模拟试卷系统&#xff08;含题库答题软件账号&#xff09; 需要在线模拟训练的题库账号请点击 小航助学编程在线模拟试卷系统&#xff08;含题库答题软件账号&#xff09;

webpack学习-2.管理资源

webpack学习-2.管理资源 1.这章要干嘛2.加载css注意顺序&#xff01; 3.总结 1.这章要干嘛 管理资源&#xff0c;什么意思呢&#xff1f;管理什么资源&#xff1f;项目中经常会 导入各种各样的css文件&#xff0c;图片文件&#xff0c;字体文件&#xff0c;数据文件等等&#…

C#-并行编程的概念及其运用

目录 一、介绍 二、并行编程 1、Parallel类 2、Timer类 1、使用Timer类 一、介绍 并行编程实际就是同一时间处理不同任务&#xff0c;可分为数据并行性&#xff08;在不同任务间同时处理相同数据&#xff09;和任务并行性&#xff08;同时执行不同的功能&#xff09;&…

一个潜水多年的体制内的生意人来实际谈谈老百姓该怎么办?

建议大家去看看天涯神贴《一个潜水多年的体制内的生意人来实际谈谈老百姓该怎么办&#xff1f;》 天涯神帖&#xff1a;《一个潜水多年的体制内的生意人来实际谈谈老百姓该怎么办&#xff1f;》 原作者&#xff1a;龙卧草庐 原文PDF链接&#xff1a;https://pan.quark.cn/s/7f8…

qt相关宏

官网宏&#xff1a; https://doc.qt.io/qt-5/qtglobal.html Q_UNLIKELY&#xff08;expr&#xff09;&#xff1a; 向编译器提示封闭条件&#xff0c;expr&#xff0c;很可能评估为false。 使用该宏可以帮助编译器优化代码。 Q_LIKELY&#xff08;expr&#xff09;&#xff1a;…

(整理中)01 - 模块机制

---- 整理自 王利涛老师 课程 文章目录 1. 可加载模块1.1 Linux内核的模块机制1.2 实验&#xff1a;hello模块1.3 内核模块的构成 KDIR : ${PWD}/../../linux-5.10.4clean:make -C ( K D I R ) M (KDIR) M (KDIR)M(PWD) modules cleanKDIR : ${PWD}/../../linux-5.10.4clean:…

Vue3网站用户引导功能【Intro.js】

一、介绍 Intro.js 是一个用于创建网站用户引导、功能介绍和教程的 JavaScript 库。它允许开发者通过步骤和提示突出显示网站上的特定元素&#xff0c;以帮助用户更好地了解和使用网站的功能。以下是 Intro.js 的一些关键特点和用法介绍&#xff1a; 更多Intro.js 功能网址&a…

mac批量修改图片格式

1. 当前窗口在word文档&#xff0c;选择工具-》宏-》点击宏 2. 弹出弹框&#xff0c;起个宏名1&#xff0c;点击2添加一个宏。 输入以下代码&#xff1a; Sub 图片格式统一()图片格式统一 宏Dim iDim Height, WeightHeight 200 改成自己的高度Weight 350 改成自己的宽度On E…

STM32-GPIO

一、GPIO简介 GPIO&#xff08;General Purpose Input Output&#xff09;通用输入输出口 可配置8种输入输出模式 引脚电平&#xff1a;0V~3.3V&#xff0c;部分引脚可容忍5V 输出模式下&#xff1a;可控制端口输出高低电平&#xff0c;用以驱动LED、控制蜂鸣器、模拟通信协议输…

MIT_线性代数笔记:第 12 讲 图、网络、关联矩阵

目录 图和网络 Graphs & Networks关联矩阵&#xff08;Incidence matrices&#xff09;矩阵的零空间矩阵列空间矩阵的左零空间矩阵的行空间 本讲讨论线性代数在物理系统中的应用。 图和网络 Graphs & Networks “图”就是“结点”和“边”的一个集合。 边线上的箭头代…

力扣11.盛最多水的容器

题目描述 思路 用双指针法。 每次向内移动较短的那个板&#xff0c;能带来更大的效益。 代码 class Solution {public int maxArea(int[] height) {int res 0;int i 0,j height.length - 1;while(i < j){res height[i] < height[j] ? Math.max((j - i) * height…

2023.12.4 关于 Spring Boot 统一异常处理

目录 引言 统一异常处理 异常全部监测 引言 将异常处理逻辑集中到一个地方&#xff0c;可以避免在每个控制器或业务逻辑中都编写相似的异常处理代码&#xff0c;这降低了代码的冗余&#xff0c;提高了代码的可维护性统一的异常处理使得调试和维护变得更加容易&#xff0c;通…

photoshop实现抠图的步骤

实现抠图的主要步骤如下&#xff1a; 打开图片&#xff1a;用Photoshop打开需要抠图的图片。 选择抠图工具&#xff1a;在Photoshop工具栏中找到“套索工具”、“魔术棒工具”、“快速选择工具”等工具&#xff0c;选择其中一个作为抠图工具。 选择抠图区域&#xff1a;用抠图…

pytorch学习9-优化器学习

系列文章目录 pytorch学习1-数据加载以及Tensorboard可视化工具pytorch学习2-Transforms主要方法使用pytorch学习3-torchvisin和Dataloader的使用pytorch学习4-简易卷积实现pytorch学习5-最大池化层的使用pytorch学习6-非线性变换&#xff08;ReLU和sigmoid&#xff09;pytorc…

Linux swatch命令教程:如何监控系统活动(附案例详解和注意事项)

Linux swatch命令介绍 Swatch&#xff0c;全称为Simple Watcher&#xff0c;是一个简单的监视器&#xff0c;设计用于监控系统活动。为了使Swatch有用&#xff0c;它需要一个配置文件&#xff0c;该文件包含要查找的模式和在找到每个模式时要执行的操作。 Linux swatch命令适…