- 921. Minimum Add to Make Parentheses Valid 使括号有效的最少添加
- 915. Partition Array into Disjoint Intervals 分割数组
- 932. Beautiful Array 漂亮数组
- 940. Distinct Subsequences II 不同的子序列 II
入职以来负责定时任务相关的业务,其底层用的是quartz框架。本篇就先简述一下quartz的执行逻辑。
quartz是通过一个调度线程不断的扫描数据库中的数据来获取到那些已经到点要触发的任务,然后调度执行它的。这个线程就是QuartzSchedulerThread类。其run方法中就是quartz的调度逻辑。
2.1获取触发器(Triggers)
run方法中首先会判断quartz框架的线程池是否有可用的线程且没有被暂停,如果没暂停且有可用线程则去获取那些将要到点触发的触发器。触发器的信息存储在qrtz_triggers表中,获取触发器的逻辑在JobStoreSupport类中,其对应的方法中就是查询qrtz_triggers表。注:JobStoreSupport中基本都是和数据库操作相关的方法。
acquireNextTriggers方法就是获取将要触发的触发器的方法,接下来看一下这个方法干了点啥。
执行了一个最多三次的循环,每次循环首先去查询表qrtz_triggers的数据,即通过selectTriggerToAcquire方法去查表,执行的sql语句如下:
TABLE_PREFIX_SUBST是表前缀,也就是QRTZ_,TABLE_TRIGGERS是表名,也就是TRIGGERS。SCHED_NAME_SUBST是内置的quartz的SCHED的名称,即QuartzScheduler。COL_开头的是对应的列名,其值为去掉COL_前缀的后部分。
selectTriggerToAcquire方法的参数和sql中的参数设置如下:
除去数据库连接Connection,另外三个参数的含义分别是trigger的nextFireTime不迟于的时间,不早于的时间和查询结果的最大值,兜底值是1。quartz做了处理,最少返回一个trigger。所以该方法干的事就是去查询qrtz_triggers表中trigger_state的值是WAITING,nextFireTime的值在参数区间中的指定数目的trigger。
2.1触发触发器(Fire Triggers)
到上面为止quartz已经获取到了将要触发的触发器,但是还没有真正的去触发它。下面继续看quartz如何去触发这些触发器。回到QuartzSchedulerThread方法中继续向下:
可以看到quartz并没有立即触发上面那一步获取到的触发器,因为这些触发器是将要触发的,其nextFireTime的值是在一个给定区间内的,可能还没有到点,只是接近到要触发的时间了。所以quartz这里做了等待的操作,如果trigger的nextFireTime比当前时间大2ms则循环等待。timeUntilTrigger就是nextFireTime和当前时间之间的差值,它在循环中不断更新,直到它的值非常小了,之后才继续向下到真正的触发逻辑。
触发时通过triggersFired方法完成,不用多说,该方法的具体实现逻辑也是在JobStoreSupport类中,一起看一下这个方法干了点啥:
可以看到是通过triggerFired方法获取到每一个trigger的TriggerFiredResult装配成一个list返回。triggerFired方法中首先检验一次触发器的状态:
接着去获取到该触发器对应的quartz的job的实例:
retrieveJob方法中是查表操作,只是查的是qrtz_job_details表:
执行的sql语句如下:
所以说retrieveJob方法传入了数据连接和trigger的jobkey两个参数,去QRTZ_JOB_DETAILS表中去查询jobkey对应的记录。该表的主键是组合主键由SCHEDULER_NAME,JOB_NAME,JOB_GROUP组成,其中SCHEDULER_NAME的值已知,参数又传入了jobkey,其中有jobName和jobGroup的值,所以可以唯一确定一行记录。
已经获取到了trigger对应的job的实例,那么继续刚才的triggersFired方法继续向下:
该方法是把触发器的状态更新为EXECUTING,是对QRTZ_TRIGGERS表操作的。紧接着:
trigger.triggered方法是去QRTZ_TRIGGERS表更新该trigger的nextFireTime和preFireTime的值。
isConcurrentExectionDisallowed方法是判断是否允许job并发执行,如果不允许,则需要把当前QRTZ_TRIGGERS表中TRIGGER_STATE的值为WAITING,ACQUIRED,PAUSED的trigger的该列的值改为BLOCKED。然后需要更新trigger。
如果nextFireTime为null,说明没有下一次触发了,本次就是最后一次执行,则该任务已经完成,state为complete,storeTrigger方法这里用于更新trigger,也可用于插入trigger。
当然最后别忘了需要返回fire的结果即一个TriggerFiredResult实例,这里返回的是一个TriggerFiredBundle实例:
TriggerTriggerBundle构造方法各个参数的含义如上图,这里要注意的是由于调用过trigger.triggered方法,当前trigger的nextFireTime和preFireTime已经更新过了,本次的scheduledFireTime已经变成了trigger的preFireTime。TriggerFiredResult中只有一个属性,就是一个TriggerFiredBundle实例,所以由它构造一个TriggerFiredResult实例向上面的调用方法返回。
OK,到这里逻辑上的触发已经完成了,但是还是没有执行job,所以让我们继续QuartzSchedulerThread中的run方法向下看
2.3执行job
根据拿到的TriggerFiredResult实例去判断要做什么操作,如果TriggerFiredBundle为null,则释放当前acquire的trigger:
在第一步获取trigger的时候,waiting状态的触发器在被获取后状态会变为acquired,而在第二步逻辑触发的时候,由于可能不支持job的并发执行,acquired的触发器的状态又有变成blocked的可能,所以该releaseAcquiredTrigger方法是操作QRTZ_TRIGGERS表,把acquired和blocked的触发器的状态都改为waiting,由于第二步逻辑触发的时候,已经判断了是最后一次触发的状态会变成complete,所以这里不用担心完成的trigger的状态被置为waiting,继续执行。
最后就是执行job的逻辑了:
JobRunShell实例中包含了job自身的信息和执行中需要的信息,qs是调度器实例。qsRsrcs是该QuartzSchedulerThread的一个属性,是其资源的集合,通过其线程池去执行该JobRunShell实例。通过调用getThreadPool().runInThread方法实现。
2.4收尾工作
可以看到在run方法最外层的while循环的最后quartz做了等待操作,改thread会等待now加上一个随机等待时间再减去now这么长的时间再继续去扫描一遍QRTZ_TRIGGERS表。isScheduleChanged方法的作用注释已经说得很明确了。
quartz执行定时任务靠的就是一个每个一段时间去扫描QRTZ_TRIGGERS表的线程来获取那些将要触发的triggers,然后对这些triggers的状态等数据进行更新,最后都没有问题则交付给线程池去执行,具体什么时候执行quartz就不管了,交给操作系统去调度了。所以说并发执行这些定时任务时,具体的执行顺序quartz也掌控不了,线程池中线程的调度最终是交由操作系统来完成的。
版权声明:「DDKK.COM 弟弟快看,程序员编程资料站」本站文章,版权归原作者所有
目录 一、前言 二、『Echarts』简介 1. 什么是『Echarts』 三、数据可视化 四、『Echarts』
Go语言最主要的特性 复制代码 代码如下: 自动垃圾回收 更丰富的内置类型 函数多返回值 错误处理 匿名函数和闭包 类型和接口 并发编程 反射 语言交互性
在ASP中,FSO的意思是File System Object,即文件系统对象。 我们将要操纵的计算机文件系统,在这里是指位于web服务器之上。所以,确认你对此拥有合适的权限。理
Java是由Sun Microsystems公司于1995年5月推出的Java面向对象程序设计语言和Java平台的总称。由James Gosling和同事们共同研发,并在1995年正式推出。 Ja
C# 是一个现代的、通用的、面向对象的编程语言,它是由微软(Microsoft)开发的,由 Ecma 和 ISO 核准认可的。 C# 是由 Anders Hejlsberg 和他的团队在 .Net
SQL 是一门 ANSI 的标准计算机语言,用来访问和操作数据库系统。SQL 语句用于取回和更新数据库中的数据。SQL 可与数据库程序协同工作,比如 MS Access、DB2、Informix、M
什么是Apache Storm? Apache Storm是一个分布式实时大数据处理系统。Storm设计用于在容错和水平可扩展方法中处理大量数据。它是一个流数据框架,具有最高的摄取率。虽然Storm
SQLite 简介 本教程帮助您了解什么是 SQLite,它与 SQL 之间的不同,为什么需要它,以及它的应用程序数据库处理方式。 SQLite是一个软件库,实现了自给自足的、无服务器的、零配置的
简介 介绍 很高兴能向大家介绍 Gradle,这是一个基于 JVM 的富有突破性构建工具。 它为您提供了: 一个像 ant 一样,通用的灵活的构建工具 一种可切换的,像 maven
hystrix介绍 Hystrix 供分布式系统使用,提供延迟和容错功能,隔离远程系统、访问和第三方程序库的访问点,防止级联失败,保证复杂的分布系统在面临不可避免的失败时,仍能有其弹性。 hyst
设计模式(Design pattern)是重构解决方案 这点很重要,尤其是现在 B/S 一统天下的局面,过早考虑设计模式,得不偿失 设计模式(Design pattern)代表了最佳的实
Ruby 是一种纯粹的面向对象编程语言。 Ruby 由日本的松本行弘(まつもとゆきひろ/Yukihiro Matsumoto)创建于1993年。 Ruby 是 "程序员的最佳朋友&quo
OWL设计的初衷是处理 web 信息 学习 OWL 之前应具备的基础知识 OWL是基于 XML 和 RDF,所以,在我们开始学习 OWL 之前,希望你对 XML、XML 命名空间以及 RDF 有基
资源描述框架(RDF)是用于描述网络资源的 W3C 标准, 比如网页的标题、作者、修改日期、内容以及版权信息 你应当具备的基础知识 在继续学习之前,我们希望你对下面的知识有基本的了解 HT
Perl 像 C 一样强大,像 awk、sed 等脚本描述语言一样方便 Perl 又名实用报表提取语言, 是 Practical Extraction and Report Language 的缩写
AWK是一个命令行工具,它和其它的 Unix/Linux 命令行工具,比如 curl 和 wget 一样,没有界面。 AWK是一门语言,对的,一门语言,而且是一个解释性编程语言。 AWK设计之初就
WSDL 是基于 XML 的用于描述 Web Services 以及如何访问 Web Services 的语言 学习 WSDL 之前应当具备的基础知识 在继续学习之前,我们希望你对下面的知识有基本
我们提供了 Web 版的 JSON 编辑器,你可以依托于我们的 Web 编辑器编辑 JavaScript 代码,然后通过点击一个按钮来查看结果 <!DOCTYPE html> <h
SVG是使用 XML 来描述二维图形和绘图程序的语言, SVG 画出来的图形具有可伸缩不失真的特性 学习之前应具备的基础知识: 继续学习之前,我们应该对以下内容有基本的了解,这样更能方便你了解一些
XML设计的初衷是用来传输和存储数据 继续学习 XML 教程前应该掌握的基础知识 在我们继续学习 XML 之前,希望你对知识有基本的了解 1、 HTML; 2、 JavaScript; 如果你
我是一名优秀的程序员,十分优秀!