调度介绍 - Quartz是怎么调起来的

简介: Quartz调度核心类QuartzSchedulerThread,是一个线程。在线程启动后,通过while循环不断去触发作业的执行。ps:源码版本2.3.2,

1.前言

上篇文章,我们介绍了quartz的调度过程及关键类。我们知道quartz作为一个调度框架,调度是框架的核心。
由上篇我们知道,在Job被调用之前,经过了几个过程,调度器启动,调度器将job和trigger加入调度器。之后就发现作业被调度了。这里再思考一下调度背后是什么?如果让我们去实现一个调度该怎么做。


2.正文

上文中Scheduler是通过Spring注入的,我们没法了解Scheduler的初始化过程。所以,我们找了个官方示例,示例中可以看到在Job被调度之前有如下3行代码:

SchedulerFactory schedFact = new org.quartz.impl.StdSchedulerFactory();

Scheduler sched = schedFact.getScheduler();

sched.start();

第一行,源码中StdSchedulerFactory的无参构造方法是个空方法,不管他。
第二行,schedFact.getScheduler()方法非常关键,该方法中初始化了QuartzScheduler,并返回了Scheduler。
第三行,调度器调用start()方法,开始启动。

2.1 调度准备

多图预警

第一,我们可以看到QuartzScheduler在初始化的时候,初始化并启动了调度线程QuartzSchedulerThread,并且该线程的标识halted = false,paused = true。源码截图如下:
1.png
2.png
3.png
7.png

第二,我们看类之间的关系。StdScheduler是Scheduler的实现类,也是QuartzScheduler的代理类。
由此我们可知,Scheduler的start()方法实际是调用了QuartzScheduler的start()方法。而start()方法中将调度线程QuartzSchedulerThread的paused = false。也就是说退出了while循环里嵌套的while,线程开始向下运行。源码截图如下:
4.1.png
4.png
5.png
5.5.png
6.png

以上是quartz调度前的准备工作。
小结:QuartzSchedulerThread线程启动后,run方法开始运行,因为halted = false故进入第一个while循环,因为halted = false,paused = true接着会进入第二个while循环,第二个循环wait-wait-wait......不停的wait,一直等到start()方法将paused设置为false。则退出嵌套的循环,开始往下运行,而往下才开始真正的调度。

2.2 准备完成,开始调度

先看一下run方法全貌:
9png.png
总体可以分为三块,前后两个同步代码块,中间夹杂了一些代码。第一个同步代码块就是刚才的嵌套while循环,用于等待调度启动,而另外一个功能类似,也是等待。这里我们重点关注的是中间的部分,图片中红框标注的。变量availThreadCount由名称可以知道,是线程池当前可用的线程数量。availThreadCount如果大于0则进入if分支执行,然后contine。这里好理解,就是去确认下当前是否有可用线程,如果有则开始进入调度逻辑。这部分代码挺长从279行到414行,我们截取关键部分看一下:
第一步,查询即将到触发时间的trigger
11.png
第二步,判断trigger是否到时间
10.png
第三步,标记trigger已触发
12png.png
第四步,通过线程池执行Job
13.png
最后,下一轮while循环。

2.3 小结

调度线程QuartzSchedulerThread进入while的无限循环,查询JobStore中即将到期的trigger,判断trigger是否到达触发时间,如果到达则通过线程池异步执行trigger绑定的Job。

3. 后记

Quartz作为一个调度框架,提供的丰富的特性,也是基于此源码量多也杂。但是作为一个调度框架核心逻辑仍是调度,我们这里通过看源码,略微一窥他调度的背后是什么。
以下是看源码时,觉得比较关键的类

  • Scheduler:调度器接口。
  • QuartzScheduler:真正调度器的实现,提供了调度器的启停、作业增删等丰富的功能。
  • StdScheduler:调度器的官方实现,实现了Scheduler,也是QuartzScheduler的代理类。
  • QuartzSchedulerThread:核心调度线程,也就是他马不停蹄的去运行Job。
  • ThreadPool:官方的线程池,用于执行Job。
  • JobRunShell:持有TriggerFiredBundle,TriggerFiredBundle持有JobDetail。JobRunShell是一个线程的实现,会真正的调用Job的execute(JobExecutionContext context)方法。

如果对你有bangz帮助,点个赞再走吧

相关文章
|
算法 Java 调度
mybatis-plus中的雪花算法
主要介绍mybatis-plus中用到的雪花算法,如有错误或未考虑完全的地方,望不吝赐教。这里默认大家对雪花算法有一定的了解哈
6613 1
mybatis-plus中的雪花算法
|
Java 应用服务中间件 网络安全
Tomcat配置ssl协议及遇到的问题https页面无法访问
Tomcat配置ssl协议及遇到的问题https页面无法访问
|
存储 关系型数据库 PostgreSQL
深入浅出PostgreSQL B-Tree索引结构
PostgreSQL 的B-Tree索引页分为几种类别 meta page root page # btpo_flags=2 branch page # btpo_flags=0 leaf page # btpo_flags=1 如果即
14886 0
|
关系型数据库 MySQL 数据库
OceanBase数据库常见问题之脚本执行失败如何解决
OceanBase 是一款由阿里巴巴集团研发的企业级分布式关系型数据库,它具有高可用、高性能、可水平扩展等特点。以下是OceanBase 数据库使用过程中可能遇到的一些常见问题及其解答的汇总,以帮助用户更好地理解和使用这款数据库产品。
|
7月前
|
人工智能 关系型数据库 分布式数据库
让数据与AI贴得更近,阿里云瑶池数据库系列产品焕新升级
4月9日阿里云AI势能大会上,阿里云瑶池数据库发布重磅新品及一系列产品能力升级。「推理加速服务」Tair KVCache全新上线,实现KVCache动态分层存储,显著提高内存资源利用率,为大模型推理降本提速。
|
Linux Docker 容器
更改docker容器中的时间而不影响宿主机
更改docker容器中的时间而不影响宿主机
|
小程序 JavaScript 前端开发
【微信小程序】--WXML & WXSS & JS 逻辑交互介绍(四)
【微信小程序】--WXML & WXSS & JS 逻辑交互介绍(四)
|
安全 应用服务中间件 Linux
windows配置supervisor实现nginx自启
windows配置supervisor实现nginx自启
383 0
|
机器学习/深度学习
YOLOv8改进 | 主干篇 | 轻量级网络ShuffleNetV2(附代码+修改教程)
YOLOv8改进 | 主干篇 | 轻量级网络ShuffleNetV2(附代码+修改教程)
655 0