quartz(7)-源码分析
定时器启动

上图通过spring加载quartz
<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
...
</bean>
SpringContext在加载SchedulerFactoryBean时会去加载他的afterPropertiesSet方法,而SchedulerFactoryBean会去与quartz的StdSchedulerFactory交互初使化配置,StdSchedulerFactory会create类QuartzScheduler,
QuartzScheduler会启动总控制线程QuartzSchedulerThread不停的轮循。
类目结构如下

1、StdSchedulerFactory是工厂类,还有一个工厂类DirectSchedulerFactory比较简单,而StdSchedulerFactory是可以加载各种属性的。属性的加载initialize方法,Contants里面都是参数,可以按说明在quartz.properties上加。
2、StdSchedule只是QuartzSchedule的一个包装类,方法更清晰。
3、QuartzScheduler是整个定时任务框架工作的核心类,上面的类图仅仅展现了QuartzScheduler中几个核心成员。
4、QuartzSchedulerResources可以认为是存放一切配置以及通过配置初始化出来的一些资源的容器,其中包括了存储job定义的jobStore
5、JobStore可以有多种实现,我们使用的是默认的RAMJobStore;
6、ThreadPool,还有一个非常重要的对象就是ThreadPool,这个线程池管理着执行我们定义的Job所需的所有线程。这个线程池的大小配置就是通过我上面提到过的“org.quartz.threadPool.threadCount”进行配置的。
QuartzScheduler另一个重要成员就是QuartzSchedulerThread,没有这个线程的话我们所有定义的任务都不会被触发执行,也就是说它是Quartz后台的“守护线程”,它不断的去查找合适的job并触发这些Job执行。
StdSchedulerFactory.getSchedule只是启动了QuartzSchedulerThread线程,开关未打开。
Scheduler.start()才是打开QuartzSchedulerThread的开关,真正开始线程轮循。
当总线程QuartzSchedulerThread处理完了数据库对TRIGGER操作后,就开始把任务放到线程中执行了。
QuartzSchedulerThread轮询流程
quartz运行时由QuartzSchedulerThread类作为主体,循环执行调度流程。JobStore作为中间层,按照quartz的并发策略执行数据库操作,完成主要的调度逻辑。JobRunShellFactory负责实例化JobDetail对象,将其放入线程池运行。LockHandler负责获取LOCKS表中的数据库锁。
处理流程
第一部分:获取trigger
1、通知JobStore获取待触发的TRIGGER
2、JobStore获取数据库锁(获取TRIGGER),获取trigger_access的行级锁
3、JobStore获取30s内触发且状态为waiting的TRIGGER
4、获取这些TRIGGER关联的job信息
5、将这些TRIGGER的状态置为acquired
6、将待触发的TRIGGER插入表中QRTZ_FIRED_TRIGGERS
7、提交获取TRIGGER的事务,行级锁被释放
8、返回待触发的TRIGGER列表
第二部分:触发trigger
10、通知JobStore触发TRIGGER
11、JobStore获取数据库锁(触发)TRIGGER,获取stat_access行级锁
12、JobStore确认TRIGGER状态
13、读取job信息
14、读取TRIGGER的calendar信息
15、更新TRIGGER的信息至executing
16、根据信息,更新TRIGGER状态至阻塞、终结、等待等状态
17、持久化TRIGGER,更新下次触发时间等
18、提交触发TRIGGER的事务,行级锁被释放
19、返回待执行的jobDetail对象
第三部分:实例化并执行Job
根据待执行的jobDetail列表,实例化job,并将其放入线程池中运行
可以看到,这个过程中有两个相似的过程:同样是对数据表的更新操作,同样是在执行操作前获取锁 操作完成后释放锁.这一规则可以看做是quartz解决集群问题的核心思想。
一个调度器实例在执行涉及到分布式问题的数据库操作前,首先要获取QUARTZ2_LOCKS表中对应当前调度器的行级锁,获取锁后即可执行其他表中的数据库操作,随着操作事务的提交,行级锁被释放,供其他调度器实例获取。
集群中的每一个调度器实例都遵循这样一种严格的操作规程,那么对于同一类调度器来说,每个实例对数据库的操作只能是串行的.而不同名的调度器之间却可以并行执行。
参考链接:http://www.cnblogs.com/davidwang456/p/4205237.html
其他参考:http://www.cnblogs.com/surprizeFuture/articles/4564293.html
quartz(7)-源码分析的更多相关文章
- quartz集群调度机制调研及源码分析---转载
quartz2.2.1集群调度机制调研及源码分析引言quartz集群架构调度器实例化调度过程触发器的获取触发trigger:Job执行过程:总结:附: 引言 quratz是目前最为成熟,使用最广泛的j ...
- 定时组件quartz系列<三>quartz调度机制调研及源码分析
quartz2.2.1集群调度机制调研及源码分析引言quartz集群架构调度器实例化调度过程触发器的获取触发trigger:Job执行过程:总结:附: 引言 quratz是目前最为成熟,使用最广泛的j ...
- (1)quartz集群调度机制调研及源码分析---转载
quartz2.2.1集群调度机制调研及源码分析 原文地址:http://demo.netfoucs.com/gklifg/article/details/27090179 引言quartz集群架构调 ...
- Quartz源码分析
先简单介绍一下quartz,Quartz是一个功能丰富的开源作业调度库,可以集成到几乎任何Java应用程序中 - 从最小的独立应用程序到最大的电子商务系统.quartz可用于创建执行数十,数百甚至数十 ...
- quartz源码分析——执行引擎和线程模型
title: quartz源码分析--执行引擎和线程模型 date: 2017-09-09 23:14:48 categories: quartz tags: [quartz, 源码分析] --- - ...
- Quartz源码——QuartzSchedulerThread.run() 源码分析(三)
QuartzSchedulerThread.run()是主要处理任务的方法!下面进行分析,方便自己查看! 我都是分析的jobStore 方式为jdbc的SimpleTrigger!RAM的方式类似分析 ...
- Quartz源码——scheduler.start()启动源码分析(二)
scheduler.start()是Quartz的启动方式!下面进行分析,方便自己查看! 我都是分析的jobStore 方式为jdbc的SimpleTrigger!RAM的方式类似分析方式! Quar ...
- Quartz源码——JobStore保存JonDetail和Trigger源码分析(一)
我都是分析的jobStore 方式为jdbc的SimpleTrigger!RAM的方式类似分析方式! {0} :表的前缀 ,如表qrtz_trigger ,{0}== qrtz_ {1}:quartz ...
- [源码分析] 定时任务调度框架 Quartz 之 故障切换
[源码分析] 定时任务调度框架 Quartz 之 故障切换 目录 [源码分析] 定时任务调度框架 Quartz 之 故障切换 0x00 摘要 0x01 基础概念 1.1 分布式 1.1.1 功能方面 ...
随机推荐
- JZOJ.5273【NOIP2017模拟8.14】亲戚
Description
- 【BZOJ3931】[CQOI2015]网络吞吐量 最大流
[BZOJ3931][CQOI2015]网络吞吐量 Description 路由是指通过计算机网络把信息从源地址传输到目的地址的活动,也是计算机网络设计中的重点和难点.网络中实现路由转发的硬件设备称为 ...
- 巨蟒python全栈开发-第10天 函数进阶
一.今日主要内容总览(重点) 1.动态传参(重点) *,** *: 形参:聚合 位置参数*=>元组 关键字**=>字典 实参:打散 列表,字符串,元组=>* 字典=>** 形参 ...
- java中的printf
转载自: http://www.cnblogs.com/healthy-tree/archive/2012/08/07/2626665.html http://www.cnblogs.com/Tank ...
- Android 点击电话号码之间拨号
点击电话号码之间拨打电话,可用通过下面的方式实现: 假设电话号码以TextView的方式显示 1.Intent方式 在TextView的响应事件中 : String phone = tvphone.g ...
- JS eval()函数
js eval()函数 这个函数可以把一个字符串当作一个JavaScript表达式一样去执行它. 举个小例子: //执行表达式 var the_unevaled_answer = & ...
- 关于oracle的sequence和trigger。
原先mysql中每个自增字段,在oracle中就需要建立一个sequence和一个trigger. 就算同一个表中有x个自增字段,那么就需要建立x个sequence和x和trigger. 实际中,我建 ...
- Java应用多机器部署定时任务解决方案
Java多机部署下定时任务的处理方案. 本文转自:http://www.cnblogs.com/xunianchong/p/6958548.html 需求: 有两台服务器同时部署了同一套代码, 代码中 ...
- python项目环境的导出、导入
导出开发环境 pip freeze > requirements.txt # 文件导出路径 导入环境 pip install -r requirements.txt # pip 则会自动下载安装 ...
- Redis、MongoDB及Memcached的区别 Redis(内存数据库)
Redis.MongoDB及Memcached的区别 Redis(内存数据库) 是一个key-value存储系统(布式内缓存,高性能的key-value数据库).和Memcached类似,它支持存储的 ...