Quartz实现原理
主要组成部分:
scheduler(调度器):将job和trigger绑定在一起
job(任务) :配置具体哪个类实现定时任务
trigger(触发器) :配置定时器参数,如:多久执行一次,执行多上次等
Quartz工作原理
分两类线程:
- Scheduler调度线程
- 任务执行线程
原理
执行常规调度的线程,常规调度线程轮询存储的所有trigger,如果有trigger到达了下一次触发的时间(用wait和notifyAll实现),则从任务执行线程池获取一个空闲线程,执行与该trigger关联的任务。
Scheduler调度线程主要有两个:
- 执行常规调度的线程
- 执行misfiredtrigger的线程,Misfire线程是扫描所有的trigger,查看是否有misfiredtrigger,如果有的话根据misfire的策略分别处理(fire now OR wait for the next fire)。
Quartz Job数据存储
Quartz中的trigger和job需要存储下来才能被使用。
Quartz中有两种存储方式:
- RAMJobStore:将trigger和job存储在内存中,RAMJobStore的存取速度非常快,但是由于其在系统被停止后所有的数据都会丢失,所以在集群应用中,必须使用JobStoreSupport。
- JobStoreSupport:是基于jdbc将trigger和job存储到数据库中。适合集群应用。
Quartz集群原理
Quartz是在同一个数据库下,其实是使用数据库(如:MySQL)做分布式锁,当任务线程执行前加锁,执行完在finally解锁。
Quartz中执行了如下SQL,以悲观锁的形式,对某条数据进行行锁,这样其他执行线程就必须等待
public static final String SELECT_FOR_LOCK = "SELECT * FROM " + TABLE_PREFIX_SUBST + TABLE_LOCKS + " WHERE " + COL_SCHEDULER_NAME + " = " + SCHED_NAME_SUBST + " AND " + COL_LOCK_NAME + " = ? FOR UPDATE";
具体流程如下:
0.调度器线程run()
1.获取待触发trigger
1.1数据库LOCKS表TRIGGER_ACCESS行加锁
1.2读取JobDetail信息
1.3读取trigger表中触发器信息并标记为"已获取"
1.4commit事务,释放锁
2.触发trigger
2.1数据库LOCKS表STATE_ACCESS行加锁
2.2确认trigger的状态(已经被获取过的trigger,就不会再执行了)
2.3读取trigger的JobDetail信息
2.4读取trigger的Calendar信息
2.3更新trigger信息
2.3commit事务,释放锁
3实例化并执行Job
3.1从线程池获取线程执行JobRunShell的run方法
参考
http://www.jianshu.com/p/bab8e4e32952
https://www.cnblogs.com/zhenyuyaodidiao/p/4755649.html
http://blog.csdn.net/wenniuwuren/article/details/45866807
http://blog.csdn.net/tercel_opening_wing/article/details/49612497