Quartz 开发随笔
控制 Quartz 只执行一次
- 纯 API 调用的代码
1 | public class ScheduleTest { |
- Spring 的 XML 配置
1 | <!-- 配置Spring项目启动后任务就执行一次 --> |
Quartz 控制线程级别的暂停、恢复、停止
Quartz 提供了暂停调度(pauseTrigger、pauseJob)、恢复调度(resumeTrigger、resumeJob)、删除调度(deleteJob)等 API,但本质都是控制 Trigger 的触发,而非直接控制任务线程的运行。如果要进行线程级别的停止,可以调用 scheduler.interrupt()
方法来实现,此时 Job 类需要实现 InterruptableJob 接口。
Quartz 的 Misfire 策略
Quartz 中有一种 Job 接口是 StatefulJob(有状态任务),简单来说这种 Job 使用在不能并发执行的场景下。比如定义了某个任务,每分钟执行一次,对一些数据进行增删操作,正常执行时,每分钟执行的 Job 互不影响;但某个时刻出现了意外,某个任务执行了三分钟,那么当在这个任务持续执行的过程中,不希望并发执行另外两次定时任务的,这就需要使用有状态任务,而没有执行的两次定时任务就是 Misfired Job。还有一种使用场景就是当执行暂停调度(pauseTrigger、pauseJob),然后执行恢复调度 (resumeTrigger、resumeJob),Quartz 会默认在恢复的时候把暂停期间没执行的任务弥补执行。对于判定是否为 Misfired Job,其实有很多条件,目前了解到的有:
- 调度暂停执行期间,预定的任务未执行
- 到执行时间时,上一个任务还未完成
- 过期时间已超过设置的
misfireThreshold
参数值 - 线程池中已没有空闲线程
- 线程池中虽有空闲线程,但有优先级更高的任务
产生 Misfire 后,Quartz 会根据 Misfire 策略进行任务的处理,其中 Trigger、CronTrigger、SimpleTrigger 的 Misfire 策略如下:
- MISFIRE_INSTRUCTION_SMART_POLICY,默认的策略
- MISFIRE_INSTRUCTION_FIRE_ONCE_NOW,立即触发一次,触发后恢复正常的频率
- MISFIRE_INSTRUCTION_DO_NOTHING,什么都不做,继续等下一次预定时间再触发
在 Spring 的 XML 配置中,Misfire 策略可以在 CronTriggerBean 中配置,同时需要在 quartz.properties
配置文件中指定 misfireThreshold
参数的值(单位为毫秒)。其中 misfireThreshold
表示实际执行时间与下一次应该执行时间之间的差值,超过这个差值就不会执行,低于这个差值就会执行。例如任务每 3 秒执行一次,配置 misfireThreshold=6000
,当暂停低于 6 秒内,Quartz 会弥补执行,超过 6 秒就不再弥补执行。具体的配置如下:
1 | <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> |
1 | 6000 = |
Quartz Cron 表达式在线生成工具
参考资料