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 中,多态主要通过虚函…...
MAX31865嵌入式驱动库:高精度RTD温度测量实战指南
1. 项目概述7Semi_MAX31865 是一款面向工业级高精度温度测量场景的嵌入式驱动库,专为 Maxim Integrated(现属 Analog Devices)MAX31865 RTD-to-digital 转换器芯片设计。该库并非简单封装,而是以底层硬件控制为核心,提…...
OpenClaw多模型切换:Qwen2.5-VL-7B与文本模型协同工作
OpenClaw多模型切换:Qwen2.5-VL-7B与文本模型协同工作 1. 为什么需要多模型协同 去年夏天,当我第一次尝试用OpenClaw自动化处理团队的知识库文档时,遇到了一个棘手的问题:有些文档包含大量截图和图表说明,而纯文本模…...
电力电子新手必看:SPWM单极性倍频调制在Simulink中的实现与优化
电力电子新手必看:SPWM单极性倍频调制在Simulink中的实现与优化 在电力电子领域,正弦脉宽调制(SPWM)技术因其简单高效而广受欢迎。对于初学者而言,单极性倍频调制作为SPWM的一种进阶实现方式,能够显著提升输…...
ncmdumpGUI高效使用指南:NCM文件转换完全掌握
ncmdumpGUI高效使用指南:NCM文件转换完全掌握 【免费下载链接】ncmdumpGUI C#版本网易云音乐ncm文件格式转换,Windows图形界面版本 项目地址: https://gitcode.com/gh_mirrors/nc/ncmdumpGUI 一、建立NCM转换认知体系 1.1 理解NCM文件加密机制 …...
2026 年1月 13 日-KB5074109(OS内部版本 26200.7623 和 26100.7623)
🔥个人主页:杨利杰YJlio❄️个人专栏:《Sysinternals实战教程》《Windows PowerShell 实战》《WINDOWS教程》《IOS教程》《微信助手》《锤子助手》 《Python》 《Kali Linux》《那些年未解决的Windows疑难杂症》🌟 让复杂的事情更…...
APM基础概念普及:应用性能管理的全面解析
在当今数字化时代,企业应用的性能直接影响着用户体验和商业成功。应用性能管理(Application Performance Management,APM)作为保障应用稳定运行的关键技术,已成为现代IT运维不可或缺的工具。本文将全面解析APM的基础概…...
博物馆展览门户|基于springboot + vue博物馆展览门户系统(源码+数据库+文档)
博物馆展览门户系统 目录 基于springboot vue博物馆展览门户系统 一、前言 二、系统功能演示 三、技术选型 四、其他项目参考 五、代码参考 六、测试参考 七、最新计算机毕设选题推荐 八、源码获取: 基于springboot vue博物馆展览门户系统 一、前言 博主…...
res-downloader:全平台网络资源下载工具的高效使用指南
res-downloader:全平台网络资源下载工具的高效使用指南 【免费下载链接】res-downloader 视频号、小程序、抖音、快手、小红书、直播流、m3u8、酷狗、QQ音乐等常见网络资源下载! 项目地址: https://gitcode.com/GitHub_Trending/re/res-downloader 当你在微信…...
基于RISC-V五级流水线设计的32位CPU:支持多种特性与AXI总线接口,适合初学者学习并附...
Riscv五级流水线32位cpu,systemverilog编写,指令集rv32i,支持数据前递,csr寄存器与中断控制器,可跑通dhrystone测试。 支持2bit饱和分支预测 本商品包括: 1.rv32五级流水线cpu代码 2.可以选择拓展的axi4总线接口代码 3…...
别只训练了!聊聊LSTM翻译模型保存的那些事儿:.h5权重、字符字典与config.json
LSTM翻译模型工程化实战:从权重保存到完整资产包的深度解析 当你花了三天三夜训练出一个效果不错的LSTM翻译模型,看着验证集上的BLEU分数终于突破30,正准备松口气时——突然意识到这个模型可能永远走不出你的Jupyter Notebook。这不是危言耸听…...
