全网最好的一篇讲解Quartz的MisFire机制

Quartz框架中MisFire的理解

如各位希望转载或引用,请注明出处,尊重原创,谢谢。如有疑问或错误,欢迎邮件沟通。
​
gitHub地址:https://github.com/thinkingfioa
邮箱地址:thinking_fioa@163.com
博客地址: https://blog.csdn.net/thinking_fioa

本文重点

Quartz框架是Java生态下非常著名的定时任务框架,包括Spring中的诸多定时任务也是依赖于Quartz框架实现的。

本文重点讲解:Quartz框架中的MisFire怎么理解,还有MissFire后的补偿机制。网上非常多的博客,完全在照搬照翻英文文档,没有任何自己的理解,没有任何参考意义。都在搬运垃圾,强烈鄙视。

1. 背景

Quartz框架是Java生态中的一套非常优秀的定时任务框架,使用Quartz框架时,需要注意Quartz强烈依赖主机时间。主机时间的任何飘动,可能导致Quartz定时任务的非预期执行或不执行。

任何定时框架,都可能存在MisFire的现象。何为MisFire,就是:周期性任务A需要在某个规定的时间执行,但是由于某种原因导致任务A未执行,称为MisFire。

Quartz常常由于下列几种情况导致任务的MisFire:

  1. Quartz的线程数较少,周期性任务较多且执行时间较长,导致某个时间点需要执行周期性任务A未被CPU调度到,导致MisFire。

  2. 将本地时间往后调整,直接跨过了周期性任务A,周期性任务A也被MisFire。

  3. 设置过去的时间为开始执行时间。例如当前时间是9:00:00,指定开始时间为7:00:00

如何设定任务的MisFire和MisFire后的补偿机制非常重要,对于改点官方文档描述较为模糊,网上一大批直接翻译官方文档的博客更是说的云里雾里。

2. 分析

本文主要从两个维度来讲解下Quartz的MisFire机制,帮助使用者能清楚理解自己的周期性任务应该如何设置,避免非预期行为出现。

2.1 如何判定一个任务是MissFire

Quartz判断一个任务是MisFire,提供了一个配置项:org.quartz.jobStore.misfireThreshold,缺省是60000ms(即60秒)。只有任务执行时间延后超过这个配置项阀值,任务才被确认为MisFire状态,随后执行约定的补偿机制。

也就是说,任务执行时间延后未超过misfireThreshold阀值,则会立即执行该任务。

2.2 判定一个任务为MissFire后,Quartz的补偿机制区别

补偿机制只有在任务确认为MisFire状态后,才会被执行。补偿机制比较容易理解,主要以CronTrigger机制为例。

2.2.1 withMisfireHandlingInstructionDoNothing

不触发立即执行,等待下次Cron触发频率到达时刻开始按照Cron频率依次执行。

2.2.2 withMisfireHandlingInstructionIgnoreMisfires

以错过的第一个频率时间立刻开始执行,重做错过的所有频率周期后,当下一次触发频率发生时间大于当前时间后,再按照正常的Cron频率依次执行

2.2.3 withMisfireHandlingInstructionFireAndProceed(默认)

以当前时间为触发频率立刻触发一次执行,然后按照Cron频率依次执行

3. 案例理解

在实际的开发中,理解misfireThreshold阀值和补偿机制非常重要,在不同的运用场景这两个配置不同,需要做到灵活运用。

在实际使用Quartz时,还有一个点需要注意:定时任务的启动时间点startAt(time)或startAtNow(),这个在预测定时任务第一次执行时非常重要。

下列以使用Cron表达式的Quartz来举例说明。

3.1 案例一

  • cron: 0 0/15 * * * ?

  • startTime(9:00:00)

  • currentTime(10:10:00)

  • org.quartz.jobStore.misfireThreshold= 15 * 60 * 1000ms

  • withMisfireHandlingInstructionFireAndProceed

周期性任务从9:00:00开始,每15分钟执行一次,misfireThreshold=15分钟。当前时间是10:10:00提交任务后,由于任务开始时间是9:00:00,应该在9:00:00、9:15:00、9:30:00、9:45:00、10:00:00执行任务,第一个任务9:00:00执行与当前的时间已经超过misfireThreshold的15分钟,意味着出现了MisFire现象,那么需按照withMisfireHandlingInstructionFireAndProceed补偿策略执行。

预期结果:立即执行一次定时任务,并在10:15:00分钟再次执行任务

3.2 案例二

  • cron: 0 0/15 * * * ?

  • startTime(9:00:00)

  • currentTime(10:10:00)

  • org.quartz.jobStore.misfireThreshold= 15 * 60 * 1000ms

  • withMisfireHandlingInstructionDoNothing

周期性任务从9:00:00开始,每15分钟执行一次,misfireThreshold=15分钟。当前时间是10:10:00提交任务后,由于任务开始时间是9:00:00,应该在9:00:00、9:15:00、9:30:00、9:45:00、10:00:00执行任务,第一个任务9:00:00执行与当前的时间已经超过misfireThreshold的15分钟,意味着出现了MisFire现象,那么需按照withMisfireHandlingInstructionDoNothing补偿策略执行。

预期结果:在10:15:00分钟执行任务

3.3 案例三

  • cron: 0 0/15 * * * ?

  • startTime(9:00:00)

  • currentTime(10:10:00)

  • org.quartz.jobStore.misfireThreshold= 100 * 60 * 1000ms

  • withMisfireHandlingInstructionDoNothing

周期性任务从9:00:00开始,每15分钟执行一次,misfireThreshold=100分钟。当前时间是10:10:00提交任务后,由于任务开始时间是9:00:00,应该在9:00:00、9:15:00、9:30:00、9:45:00、10:00:00执行任务,第一个任务9:00:00执行与当前的时间未超过misfireThreshold的100分钟,意味着任务未出现misFire现象。所有任务立即执行下

预期结果:立即执行5次任务,并在10:15:00分钟再次执行任务

参考资料

  • 12
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
Quartz是一个强大的作业调度框架,可以用来实现定时任务。使用Quartz中的反射机制可以方便地调用应用程序中的方法。 要使用Quartz的反射机制调用应用程序中的方法,需要执行以下步骤: 1. 创建一个实现了Job接口的类,该类中需要实现execute方法,该方法中实现需要执行的业务逻辑。 2. 在该类中定义一个名为"methodName"的字符串变量,用于指定要调用的方法名。 3. 在execute方法中使用反射机制调用应用程序中的方法。具体实现方法如下: ``` Class<?> clazz = Class.forName("应用程序中的类名"); Object obj = clazz.newInstance(); Method method = clazz.getMethod(methodName, 参数类型); method.invoke(obj, 参数值); ``` 其中,"应用程序中的类名"是指需要调用的类的全路径名,"methodName"是指需要调用的方法名,"参数类型"和"参数值"分别指定需要传递给该方法的参数类型和参数值。 4. 在Quartz中配置JobDetail和Trigger,将实现了Job接口的类和要调用的方法名传递给JobDataMap中,然后在execute方法中获取JobDataMap中的方法名,并使用反射机制调用应用程序中的方法。 ``` JobDetail jobDetail = JobBuilder.newJob(实现了Job接口的类.class).build(); jobDetail.getJobDataMap().put("methodName", "要调用的方法名"); Trigger trigger = TriggerBuilder.newTrigger().build(); scheduler.scheduleJob(jobDetail, trigger); ``` 在execute方法中获取JobDataMap中的方法名,并使用反射机制调用应用程序中的方法: ``` String methodName = jobExecutionContext.getJobDetail().getJobDataMap().getString("methodName"); Class<?> clazz = Class.forName("应用程序中的类名"); Object obj = clazz.newInstance(); Method method = clazz.getMethod(methodName, 参数类型); method.invoke(obj, 参数值); ``` 通过以上步骤,就可以使用Quartz的反射机制调用应用程序中的方法了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值