Quartz 相关线程
我们在前面文章中说到过Quartz涉及到的线程,但是散落在几篇文章中,不好找。而Quartz涉及到的线程对于理解Quartz也比较重要,所以今天专门提取出来单独说一下。
Quartz中的主要线程:
-
任务调度线程QuartzSchedulerThread
-
任务执行线程
-
Misfire处理线程
-
ClusterManager线程
任务调度线程 QuartzSchedulerThread
QuartzSchedulerThread是任务调度线程,他的职责是对满足触发条件(nextFireTimer到了)的注册到JobStore的Trigger分配给可用的任务执行线程去执行。
QuartzSchedulerThread启动
任务调度线程QuartzSchedulerThread是在调度器Scheduler创建的时候启动的。
应用层通过以下调用创建Scheduler:
Scheduler sche = new StdSchedulerFactory().getScheduler();
一般情况下通过StdSchedulerFactory构建Scheduler,getScheduler首先尝试从SchedulerRepository获取Schedule,首次运行获取不到,则通过instantiate()方法获取。
public Scheduler getScheduler() throws SchedulerException {if (cfg == null) {initialize();}SchedulerRepository schedRep = SchedulerRepository.getInstance();Scheduler sched = schedRep.lookup(getSchedulerName());if (sched != null) {if (sched.isShutdown()) {schedRep.remove(getSchedulerName());} else {return sched;}} sched = instantiate();return sched;
}
instantiate()方法特别特别特别长,几乎就是在这里完成Quartz所有相关组件的初始化的。
其中会创建QuartzScheduler,之后会将QuartzScheduler包装到stdScheduler中存入SchedulerRepository中。
instantiate()创建QuartzScheduler是调用的构造方法:
public QuartzScheduler(QuartzSchedulerResources resources, long idleWaitTime, @Deprecated long dbRetryInterval)throws SchedulerException {this.resources = resources;if (resources.getJobStore() instanceof JobListener) {addInternalJobListener((JobListener)resources.getJobStore());}this.schedThread = new QuartzSchedulerThread(this, resources); ThreadExecutor schedThreadExecutor = resources.getThreadExecutor();schedThreadExecutor.execute(this.schedThread);if (idleWaitTime > 0) { this.schedThread.setIdleWaitTime(idleWaitTime);}jobMgr = new ExecutingJobsManager();addInternalJobListener(jobMgr);errLogger = new ErrorLogger();addInternalSchedulerListener(errLogger);signaler = new SchedulerSignalerImpl(this, this.schedThread);getLog().info("Quartz Scheduler v." + getVersion() + " created.");
}
可以看到构造方法中创建了QuartzSchedulerThread对象,之后获取ThreadExecutor(一般情况下为DefaultThreadExecutor)并通过调用其execute方法启动QuartzSchedulerThread线程:
public class DefaultThreadExecutor implements ThreadExecutor {public void initialize() {}public void execute(Thread thread) {thread.start();}}
QuartzSchedulerThread的运行
其实就是他的run方法,我们也大概分析过,其主要逻辑是:
-
从作业执行线程池获取availThreadCount,也就是当前可用的线程数
-
调用JobStore的acquireNextTriggers方法,获取特定短时间(idleWaitTime,默认30秒)内可能需要被触发的,数量不超过availThreadCount的触发器
-
调用JobStore的triggersFired方法对获取到的可能需要被触发的触发器进行二次加工,再次获取到最终的待触发器结果集
-
循环处理最终的待处理触发器结果集中的每一个需要被触发的触发器
-
用JobRunShell包装该触发器,送给线程池执行该触发器关联的作业
好了,作业调度线程QuartzSchedulerThread我们就基本搞清楚了。
作业执行线程
Quartz的作业执行线程是放在线程池中进行管理的,默认是SimpleTreadPool,有关SimpleThreadPool我们前面专门有一篇文章介绍过,这里就不再赘述了。
作业执行线程和作业调度线程一样,也是在作业调度器Scheduler创建后立即启动,这个过程同样也是在StdSchedulerFactory的instantiate()方法中完成的:
instantiate()创建SimpleThreadPool之后会调用SimpleThreadPool的initialize方法,根据配置文件指定的任务执行线程数完成工作线程的初始化和启动。比如配置文件设置为10则初始化10个工作线程并逐个启动。作业执行线程的初始化及启动的详细过程请参考Quartz - SimpleThreadPool。
MisfireHandler线程
如果你的项目使用RAMJobStore,而不是JDBC-based JobStore(指需要持久化到数据库的JobStore),那么就不存在Misfire处理线程。
因为RAMJobStore在处理正常触发的过程中顺便就处理了Misfire,所以就不再需要其他处理机制了,这部分我们在前面的文章中也分析过Quartz - Misfire (for RAMJobstore)。
JDBC-based JobStore在处理正常触发的时候只获取未错过触发时间的触发器,对于错过触发时间的、也就是Misfire的触发器就需要另外的机制来处理。
Misfire处理线程就是Quartz采用JDBC-based JobStore的情况下用来处理错过触发时机的触发器的线程。
MisfireHandler启动
MisfireHandler定义在JobStoreSupport类中,JobStoreSupport是JobStore的JDBC-based JobStore的虚拟类,Quartz主要提供了两个基于JDBC的JobStore的实现:JobStoreTX、JobStoreCMT。JDBC-based JobStore详细内容请参考Quartz - JDBC-Based JobStore,今天主要分析MisfireHandler。
我们在应用中创建任务调度器Scheduler后需要调用他的start方法:
Scheduler sche = new StdSchedulerFactory().getScheduler();sche.scheduleJob(jobDetail,trigger);sche.start();
这个start方法会调用到JobStore的schedulerStarted()方法,如果我们应用中采用的是JDBC-based JobStore的话,会调用到JobStoreSupport的schedulerStarted(),其中会创建MisfireHandler之后调用MisfireHandler的initialize():
misfireHandler = new MisfireHandler();if(initializersLoader != null)misfireHandler.setContextClassLoader(initializersLoader);misfireHandler.initialize();
Misfire的initialize将创建好的MisFireHandle线程交给ThreadExecutor启动。
public void initialize() {ThreadExecutor executor = getThreadExecutor();executor.execute(MisfireHandler.this);}
MisfireHandle的运行
也就是MisfireHandle的run方法。处理逻辑和RAMJobStore处理misfired trigger的逻辑类似,只不过MisfireHandle的所有处理逻辑都是通过数据库操作完成的。
JDBC-Based JobStore对应的表结构我们会找机会专门分析,这里就不详细展开了。
MisfireHandle的run方法的主要逻辑为:
-
从数据库中获取在WAITING(等待执行)状态、下次执行时间小于msifiredtime(当前时间 - MisfireThreshold)的触发器,也就是错过触发时间的触发器
-
为了避免存在大量misfired trigger的情况下,一次处理太多数据影响其他正常触发器的执行,MisfireHandle线程每次仅获取部分而不是全部misfired trigger(参数maxToRecoverAtATime指定,默认为20)
-
对获取到的每一个错过执行时间的触发器(misfired trigger),调用触发器的updateAfterMisfire方法获取下次执行时间,updateAfterMisfire方法我们在上一篇讲Misfire处理策略的文章中说过,就是根据触发器的处理策略获取下次执行时间
-
updateAfterMisfire方法执行后,获取到的触发器的下次执行时间如果不为空的话,更新到数据库中,等待正常的任务执行线程调度执行
ClusterManager线程
与MisfiredHandle一样,ClusterManager线程也是JDBC-Based JobStore特有的。
顾名思义,ClusterManager线程与集群有关系,JDBC-Based JobStore是可以支持Quartz的集群部署的,在集群环境下,Quartz服务节点可能会down机、掉线,从而影响任务的执行,ClusterManager线程就是负责检查Quartz服务节点的在线状态的,如果发生掉线后,将该服务节点负责的触发器交给其他服务节点来处理。
具体逻辑等到我们分析完Quartz Cluster之后补充。
相关文章:
Quartz 相关线程
我们在前面文章中说到过Quartz涉及到的线程,但是散落在几篇文章中,不好找。而Quartz涉及到的线程对于理解Quartz也比较重要,所以今天专门提取出来单独说一下。 Quartz中的主要线程: 任务调度线程QuartzSchedulerThread 任务执…...

【QED】爱丽丝与混沌的无尽海
文章目录 题目题目描述输入输出格式数据范围测试样例 思路代码复杂度分析时间复杂度空间复杂度 题目 题目链接🔗 题目描述 如图所示,爱丽丝在一个3x3的迷宫之中,每个方格中标有 1 − 9 1-9 1−9各不相同的数字,爱丽丝可以从一格…...
IO模型学习
背景知识 Socket 套接字。 客户端和服务端通信时,客户端需要数据出口,服务端需要数据入口,这两个出入口就是Socket。数据接收方新建socket后需要绑定ip和端口号,这样客户端才能链接上socket。连接的过程就是 三次握手 FD file …...

Doxygen 使用指南
Doxygen 是一个文档生成工具,可以从源代码中的注释生成高质量的文档,支持多种编程语言(如 C/C、Python、Java 等)。以下是 Doxygen 的基本使用方法。 1. 安装 Doxygen 1.1 下载 Doxygen 访问 Doxygen 官网。根据操作系统选择合适…...

设计模式与游戏完美开发(2)
更多内容可以浏览本人博客:https://azureblog.cn/ 😊 该文章主主题内容均来自《设计模式与游戏完美开发》—蔡升达 第二篇 基础系统 第四章 游戏主要类——外观模式(Facade) 一、游戏子功能的整合 一个游戏程序常常由内部数个不…...
Coroutine 基础三 —— 结构化并发(二)
1、协程的结构化异常管理 如果一个协程抛异常,它所在的整个协程树上的其他协程(向上是父协程到根协程,向下是所有后代协程)都会被取消。因此协程发生异常的后果是十分严重的。 先讲原理,再说解决方案。 协程异常的处…...

GXUOJ-算法-第一次作业
1.整数划分 问题描述 GXUOJ | 整数划分 题解 #include<bits/stdc.h> using namespace std; const int N1010,mod1e97;int n; int f[N];int main(){cin>>n;f[0]1;for(int i1;i<n;i){for(int ji;j<n;j){f[j](f[j]f[j-i])%mod;}}cout<<f[n]; } 2.汉诺塔…...

Springboot项目Druid运行时动态连接多数据源的功能
项目支持多数据库连接是个很常见的需求,这不仅是要在编译前连已经知道的多个数据库,有时还要在程序运行时连后期增加的多个数据源来获得数据。 一、编译前注册数据库连接 1.引入依赖包 <!-- springboot 3.x --><dependency><groupId&g…...
字符串匹配——KMP算法
前言 刷到字符串匹配的力扣题了【28. 实现 strStr() 】,这题简单吧用库函数做就可以,说难吧,就得引出大名鼎鼎的线性匹配算法——KMP。 目录 KMP 算法背景与原理算法优势 前缀表1. 构建Next数组2. 搜索匹配 KMP 算法背景与原理 KMP&#x…...

Qt开发技术【下拉复选框 MultiSelectComboBox 自定义全选项】
继承ComboBox完成下拉复选框 自定义全选项 效果图 整个控件继承于QCombobox类。主要修改QLineEdit、QListWidget这两部分,QComboBox提供如下接口,可以将这两部分设置为新建的QLineEdit、QListWidget对象 CMultiSelectComboBox::CMultiSelectComboBo…...

20_HTML5 SSE --[HTML5 API 学习之旅]
HTML5 Server-Sent Events (SSE) 是一种技术,它允许服务器向浏览器推送更新。与传统的轮询不同,SSE提供了真正的单向实时通信通道:服务器可以主动发送数据到客户端,而不需要客户端发起请求。这对于实现实时更新的应用非常有用&…...

jetson Orin nx + yolov8 TensorRT 加速量化 环境配置
参考【Jetson】Jetson Orin NX纯系统配置环境-CSDN博客 一 系统环境配置: 1.更换源: sudo vi /etc/apt/sources.list.d/nvidia-l4t-apt-source.list2.更新源: sudo apt upgradesudo apt updatesudo apt dist-upgrade sudo apt-get updat…...

Android Studio IDE环境配置
需要安装哪些东西: Java jdk Java Downloads | OracleAndroid Studio 下载 Android Studio 和应用工具 - Android 开发者 | Android DevelopersAndroid Sdk 现在的Android Studio版本安装时会自动安装,需要注意下安装的路径Android Studio插件…...
PTA 7-2 0/1背包问题(回溯法) 作者 王东 单位 贵州师范学院
0/1背包问题。给定一载重量为W的背包及n个重量为wi、价值为vi的物体,1≤i≤n,要求重量和恰好为W具有最大的价值。 输入格式: 第一行输入背包载重量W及背包个数n,再依次输入n行,每行为背包重量wi和价值vi。 输出格式: 第一行输出装入背包内…...

Matlab环形柱状图
数据准备: 名称 数值 Aa 21 Bb 23 Cc 35 Dd 47 保存为Excel文件后: % Load data from Excel file filename data.xlsx; % Ensure the file is in the current folder or provide full path dataTable readtable(filena…...

【AI大模型】探索GPT模型的奥秘:引领自然语言处理的新纪元
目录 🍔 GPT介绍 🍔 GPT的架构 🍔 GPT训练过程 3.1 无监督的预训练语言模型 3.2 有监督的下游任务fine-tunning 🍔 小结 学习目标 了解什么是GPT.掌握GPT的架构.掌握GPT的预训练任务. 🍔 GPT介绍 GPT是OpenAI公…...
5.Python爬虫相关
爬虫 爬虫原理 爬虫,又称网络爬虫,是一种自动获取网页内容的程序。它模拟人类浏览网页的行为,发送HTTP请求,获取网页源代码,再通过解析、提取等技术手段,获取所需数据。 HTTP请求与响应过程 爬虫首先向…...
Windows系统上配置eNSP环境的详细步骤
华为eNSP(Enterprise Network Simulation Platform)是一款针对华为数通网络设备的网络仿真平台,用于辅助工程师进行网络技术学习、方案验证和故障排查等工作。以下是在Windows系统上配置eNSP环境的详细步骤: 1. 准备工作 下载安…...

Database.NET——一款轻量级多数据库客户端工具
文章目录 Database.NET简介下载使用使用场景总结 Database.NET简介 Database.NET 是一个功能强大且易于使用的数据库管理工具,适用于多种数据库系统。它为开发者和数据库管理员提供了一个统一的界面,可以方便地管理和操作不同类型的数据库。 支持的数据…...

新浪微博C++面试题及参考答案
多态是什么?请详细解释其实现原理,例如通过虚函数表实现。 多态是面向对象编程中的一个重要概念,它允许不同的对象对同一消息或函数调用做出不同的响应,使得程序具有更好的可扩展性和灵活性。 在 C 中,多态主要通过虚函…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...
拉力测试cuda pytorch 把 4070显卡拉满
import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...
今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存
文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...

算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...
安卓基础(aar)
重新设置java21的环境,临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的: MyApp/ ├── app/ …...

无人机侦测与反制技术的进展与应用
国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机(无人驾驶飞行器,UAV)技术的快速发展,其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统,无人机的“黑飞”&…...
NPOI Excel用OLE对象的形式插入文件附件以及插入图片
static void Main(string[] args) {XlsWithObjData();Console.WriteLine("输出完成"); }static void XlsWithObjData() {// 创建工作簿和单元格,只有HSSFWorkbook,XSSFWorkbook不可以HSSFWorkbook workbook new HSSFWorkbook();HSSFSheet sheet (HSSFSheet)workboo…...
BLEU评分:机器翻译质量评估的黄金标准
BLEU评分:机器翻译质量评估的黄金标准 1. 引言 在自然语言处理(NLP)领域,衡量一个机器翻译模型的性能至关重要。BLEU (Bilingual Evaluation Understudy) 作为一种自动化评估指标,自2002年由IBM的Kishore Papineni等人提出以来,…...