在上一篇《Quartz的负载均衡如何实现》文章中说过Quartz的线程模型,提到了MisFire任务是由MisfireHandler线程专门进行处理的,本文主要是来了解下该部分功能是如何实现的。
源码分析:
MisfireHandler线程定义在JobStoreSupport类中,在初始化的时候会将自己注册到线程池中:
public void initialize() {
ThreadExecutor executor = getThreadExecutor();
executor.execute(MisfireHandler.this);
}
来看下它的run()方法:
主要分成三步:
- 获取Misfire的trigger
- 通知QuartzSchedulerThread触发这些trigger的执行
- sleep一段时间,目的是At least a short pause to help balance threads(暂时不太理解这句话的含义)
来分析下如何获取Misfire的trigger,核心是manager()方法中的doRecoverMisfires():
![](https://img-blog.csdnimg.cn/20200204221318521.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3pjMTk5MjEyMTU=,size_16,color_FFFFFF,t_70)
countMisfiredTriggersInState()用于查看是否确实存在Misfire的job,避免数据库加锁这一操作。Misfire判断依据是:status = WAITING, next_fire_time < current_time - misfirethreshold(可配置,默认1min)。即默认情况下,如果超过了Trigger本应触发时间60s,这次Trigger便不会再进行恢复了!
但是如果确实存在Misfire的job,则会调用recoverMisfiredJobs()方法中的doUpdateOfMisfiredTrigger()方法修改Misfire Trigger的next fired time ,然后通知任务选取线程去调度,对这些Trigger进行恢复,默认情况一次最多同时恢复20个Trigger(maxToRecoverAtATime参数控制)。
![](https://img-blog.csdnimg.cn/20200204221526482.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3pjMTk5MjEyMTU=,size_16,color_FFFFFF,t_70)
核心是updateAfterMisfire()方法,内部根据程序选取的Misfire策略设置Trigger的setNextFireTime(cal)进行恢复,本文接下来会说明一些Misfire策略。
触发trigger执行的代码逻辑就比较简单了:
if (recoverMisfiredJobsResult.getProcessedMisfiredTriggerCount() > 0) {
signalSchedulingChangeImmediately(recoverMisfiredJobsResult.getEarliestNewTime());
}
内部通过sigLock.notifyall(),唤醒QuartzSchedulerThread线程调度执行任务:
常用的MisFire策略:
介绍下SimpleScheduler一些常用的Misfire策略:
![](https://img-blog.csdnimg.cn/20200204221932246.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3pjMTk5MjEyMTU=,size_16,color_FFFFFF,t_70)
withMisfireHandlingInstructionIgnoreMisfires
所有MisFire的Trigger会马上执行
withMisfireHandlingInstructionFireNow(默认)
立即执行Trigger,该策略适用于只执行一次的Trigger
withMisfireHandlingInstructionNextWithExistingCount
下一次Trigger时间到的时候执行任务,总次数不变
withMisfireHandlingInstructionNextWithRemainingCount(默认)
下一次Trigger时间到的时候执行任务,起始次数清零,重新开始执行
withMisfireHandlingInstructionNowWithExistingCount(默认)
立即执行Trigger,循环开始周期以当前时间为基准,总次数不变
withMisfireHandlingInstructionNowWithRemainingCount
立即执行Trigger,循环开始周期以当前时间为基准,起始次数清零,重新开始执行
默认情况下,Quartz的Scheduler会根据Trigger的触发次数来选择不同的MisFire策略:
![](https://img-blog.csdnimg.cn/20200204222722984.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3pjMTk5MjEyMTU=,size_16,color_FFFFFF,t_70)
参考:
https://www.cnblogs.com/skyLogin/p/6927629.html(Misfire策略)
https://www.jianshu.com/p/6afa510fa2ff(Quartz源码阅读)