感谢兄台: 《quartz-misfire 错失、补偿执行

misfire定义

misfire:被错过的执行任务策略

misfire重现——CronTrigger

job任务类:

package org.quartz.examples.example5;

import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.PersistJobDataAfterExecution; import java.text.SimpleDateFormat;
import java.util.Date; /**
* <pre>
* 任务job。
* 因为@DisallowConcurrentExecution注解,所以这个job不可以被多个定时器或触发器同时执行,否则会触发定时器的misfire,就需要我们定义好定时器的misfire策略。
* 如果不定义misfire,会出现
* </pre>
*/
@PersistJobDataAfterExecution //持久化JobDataMap里的数据,使下一个定时任务还能获取到这些值
@DisallowConcurrentExecution //禁止并发多任务执行,所以永远只有一个任务在执行中
public class StatefulDumbJob implements Job { //任务执行计数器
public static final String NUM_EXECUTIONS = "NumExecutions";
public static final String EXECUTION_DELAY = "ExecutionDelay";
public static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); //必须要有public修饰的无参构造函数
public StatefulDumbJob() {
} //定时器执行方法
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("---" + context.getJobDetail().getKey() + " executing. [" + SDF.format(new Date()) + "]");
//获得带状态集合
JobDataMap map = context.getJobDetail().getJobDataMap(); int executeCount = 0;
if (map.containsKey(NUM_EXECUTIONS)) {
executeCount = map.getInt(NUM_EXECUTIONS);
} executeCount++; map.put(NUM_EXECUTIONS, executeCount); System.out.println(" -" + context.getJobDetail().getKey() + " complete (" + executeCount + ").[" + SDF.format(new Date())+ "]"); } }

定时器类:

package org.quartz.examples.example5;

import static org.quartz.CronScheduleBuilder.cronSchedule;
import static org.quartz.DateBuilder.nextGivenSecondDate;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger; import java.util.Date; import org.quartz.CronExpression;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.SchedulerFactory;
import org.quartz.impl.StdScheduler;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; /**
* <pre>
此类演示了如何定义定时器的misfire策略。misfire:被错过的执行任务策略
* </pre>
*/
public class MisfireExample_CronScheduleBuilder {
static final Logger LOG = LoggerFactory.getLogger(MisfireExample_CronScheduleBuilder.class); public static void main(String[] args) throws Exception {
// 初始化一个调度工厂,并实例化一个调度类
SchedulerFactory sf = new StdSchedulerFactory();
// Scheduler sched = sf.getScheduler();
StdScheduler sched = (StdScheduler) sf.getScheduler(); // 第一个参数:null就是默认当前时间,也可以指定时间
// 第二个参数:把一分钟按10进行划分,也就是60/10等份。
// 举例:当前时间是10:26:04,那么startTime就是10:30:00。当前时间是10:38:31,那么startTime就是10:40:00。
Date startTime = nextGivenSecondDate(null, 10);
JobDetail job = newJob(StatefulDumbJob.class).withIdentity("job1", "group1")
// .usingJobData(StatefulDumbJob.EXECUTION_DELAY, 30000L)
.build();
String cron = "0/2 * * * * ?"; // 每2秒执行一次 CronScheduleBuilder cronScheduleBuilder = cronSchedule(new CronExpression(cron)); // ========================================================================
// ======================== misfire定义,开始 =======================
// ======================================================================== /*
设置misfire策略:CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING = 2
——不触发立即执行
——等待下次Cron触发频率到达时刻开始按照Cron频率依次执行
*/
cronScheduleBuilder.withMisfireHandlingInstructionDoNothing(); /*
设置misfire策略:Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY = -1
——以错过的第一个频率时间立刻开始执行 ——重做错过的所有频率周期 ——当下一次触发频率发生时间大于当前时间以后,按照Interval的依次执行剩下的频率
——共执行RepeatCount+1次
*/
// cronScheduleBuilder.withMisfireHandlingInstructionIgnoreMisfires(); /*
* 设置misfire策略:CronTrigger.MISFIRE_INSTRUCTION_FIRE_ONCE_NOW = 1
* 以当前时间为触发频率立刻触发一次执行,然后按照Cron频率依次执行
*/
// cronScheduleBuilder.withMisfireHandlingInstructionFireAndProceed(); // ========================================================================
// ======================== misfire定义,结束 =======================
// ======================================================================== CronTrigger trigger = newTrigger().withIdentity("trigger1", "group1").startAt(startTime)
.withSchedule(cronScheduleBuilder).build(); // CronTrigger默认misfire策略是: org.quartz.Trigger.MISFIRE_INSTRUCTION_SMART_POLICY = 0
int misfireInstruction = trigger.getMisfireInstruction();
LOG.info("当前misfire策略:" + misfireInstruction); Date ft = sched.scheduleJob(job, trigger);
LOG.info(job.getKey().toString()); sched.start();
LOG.info("调度器启动,主线程睡眠15秒!!!!调度器内任务线程继续执行。");
Thread.sleep(15L * 1000L); // // 暂停触发器
// sched.pauseTrigger(trigger.getKey());
// // 继续触发器
// sched.resumeTrigger(trigger.getKey()); // 暂停执行任务
sched.pauseJob(job.getKey());
LOG.info("调度器暂停执行定时器,主线程睡眠11秒!!!!会错过执行job1的N次定时任务。模拟当定时器的执行线程由于抢不到CPU时间或其他事件错过执行的情况。");
Thread.sleep(11L * 1000L);
// 继续执行任务
sched.resumeJob(job.getKey()); //当定时器得到继续执行的命令时,被错过执行的任务次数,就会按照misfire的定义去执行 LOG.info("调度器继续执行定时器,主线程睡眠15秒!!!!调度器内任务线程继续执行。");
Thread.sleep(15L * 1000L); LOG.info("调度器终止执行!!!!");
sched.shutdown(true);
} }

 misfire重现——SimpleTrigger

CronTrigger的misfire策略经本人亲自测试,注释全部可靠,SimpleTrigger全部来自以下兄台文章注释,实际结果请各位亲自实验。

感谢兄台: 《quartz-misfire 错失、补偿执行

SimpleTrigger默认misfire策略也是: org.quartz.Trigger.MISFIRE_INSTRUCTION_SMART_POLICY = 0

//定义触发器,2秒执行一次,循环5次,总共执行6次
SimpleScheduleBuilder simpleScheduleBuilder = simpleSchedule().withIntervalInSeconds(2).withRepeatCount(5);
// .repeatForever(); //无限循环 /*
设置misfire策略为:SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT = 5
——不触发立即执行
——等待下次触发频率周期时刻,执行至FinalTime的剩余周期次数
——以startTime为基准计算周期频率,并得到FinalTime
——即使中间出现pause,resume以后保持FinalTime时间不变
*/
simpleScheduleBuilder.withMisfireHandlingInstructionNextWithExistingCount(); /*
设置misfire策略为:SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT = 4
——不触发立即执行
——等待下次触发频率周期时刻,执行至FinalTime的剩余周期次数
——以startTime为基准计算周期频率,并得到FinalTime
——即使中间出现pause,resume以后保持FinalTime时间不变
*/
simpleScheduleBuilder.withMisfireHandlingInstructionNextWithRemainingCount(); /*
设置misfire策略为:SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT = 3
——以当前时间为触发频率立即触发执行
——执行至FinalTIme的剩余周期次数
——以调度或恢复调度的时刻为基准的周期频率,FinalTime根据剩余次数和当前时间计算得到
——调整后的FinalTime会略大于根据starttime计算的到的FinalTime值
*/
simpleScheduleBuilder.withMisfireHandlingInstructionNowWithRemainingCount(); /*
设置misfire策略为:SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT = 2
——以当前时间为触发频率立即触发执行
——执行至FinalTIme的剩余周期次数
——以调度或恢复调度的时刻为基准的周期频率,FinalTime根据剩余次数和当前时间计算得到
——调整后的FinalTime会略大于根据starttime计算的到的FinalTime值
*/
simpleScheduleBuilder.withMisfireHandlingInstructionNowWithExistingCount(); /*
设置misfire策略为:SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW = 1
——以当前时间为触发频率立即触发执行
——执行至FinalTIme的剩余周期次数
——以调度或恢复调度的时刻为基准的周期频率,FinalTime根据剩余次数和当前时间计算得到
——调整后的FinalTime会略大于根据starttime计算的到的FinalTime值
*/
simpleScheduleBuilder.withMisfireHandlingInstructionFireNow(); /*
设置misfire策略为:Trigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY = -1
——以错过的第一个频率时间立刻开始执行
——重做错过的所有频率周期
——当下一次触发频率发生时间大于当前时间以后,按照Interval的依次执行剩下的频率
——共执行RepeatCount+1次
*/
simpleScheduleBuilder.withMisfireHandlingInstructionIgnoreMisfires();

quartz2.3.0(五)制定错过执行任务的misfire策略,用pause,resume模拟job暂停执行和继续执行的更多相关文章

  1. quartz2.3.0系列目录——带您由浅入深全面掌握quartz2.3.0

    quartz2.3.0系列目录 官网下载地址:http://www.quartz-scheduler.org/downloads/ 本系列demo全部来源于官网,仅仅是简化和汉化了注释!一部分代码de ...

  2. spring3.2.8+quartz2.2.0(比较全,对比quartz1.x的配置)

    spring3.2.8 + quartz2.2.0报错: java.lang.IncompatibleClassChangeError: class org.springframework.sched ...

  3. SpringBoot2.0.3整合Quartz2.3.0实现定时任务

    转载:https://www.cnblogs.com/ealenxie/p/9134602.html 关于别人写的quartz学习的地址:https://blog.csdn.net/lkl_csdn/ ...

  4. quartz2.3.0(十三)数据库持久化定时器job任务和trigger触发器,在多个调度器实例情况下,由其它调度器实例恢复执行调度器宕机的job任务

    一.初始化数据库11张quartz表:qrtz_*   先从官网下载好quartz2.3.0包:http://www.quartz-scheduler.org/downloads/ 解压后进入目录:q ...

  5. quartz2.3.0(十)xml配置方式定义quartz定时任务

    1.新增pom依赖 除了按照<quartz2.3.0系列目录——带您由浅入深全面掌握quartz2.3.0>添加依赖之外,pom.xml里新增加依赖: <dependency> ...

  6. 第七节:Trigger(SimpleTrigger、CronTrigger)哑火(MisFire)策略 :

    一. 简介 1. 什么是哑火 由于某些原因导致触发器(trigger)在该触发的时候没有得到触发,后续对应的解决策略即为哑火策略.(个人理解) 2. 哑火触发的条件 ①:所有的工作线程都在忙碌,导致某 ...

  7. Quartz任务调度:MisFire策略和源码分析

    Quartz是为大家熟知的任务调度框架,先看看官网的介绍: ---------------------------------------------------------------------- ...

  8. Quartz.Net系列(十六):Misfire策略在SimpleScheduler和CronScheduler中的使用

    1.场景 ①因为工作线程都在忙碌,所以导致某些Trigger得不到触发 也就是默认10个工作线程而我有15个Trigger同时触发 这就导致有5个不能被触发,而不幸的是Trigger所关联的Job执行 ...

  9. java线程池与五种常用线程池策略使用与解析

    背景:面试中会要求对5中线程池作分析.所以要熟知线程池的运行细节,如CachedThreadPool会引发oom吗? java线程池与五种常用线程池策略使用与解析 可选择的阻塞队列BlockingQu ...

随机推荐

  1. 2019SDSC夏令营游记

    Day 1 2019.7.22 晴 第一天夏令营,是在一所大学举办的. 到之前的我好兴奋,要提前看一下大学到底是什么样的. 聊了一上午的天 坐了一上午的公交终于到了目的地,下午很自由,自己在宿舍里面休 ...

  2. Android入门教程(四)

    关注我,每天都有优质技术文章推送,工作,学习累了的时候放松一下自己. 本篇文章同步微信公众号 欢迎大家关注我的微信公众号:「醉翁猫咪」 学习Android要掌握Android程序结构,和通信技术,和如 ...

  3. 原创:协同过滤之spark FP-Growth树应用示例

    上一篇博客中,详细介绍了UserCF和ItemCF,ItemCF,就是通过用户的历史兴趣,把两个物品关联起来,这两个物品,可以有很高的相似度,也可以没有联系,比如经典的沃尔玛的啤酒尿布案例.通过Ite ...

  4. GoCN每日新闻(2019-10-22)

    GoCN每日新闻(2019-10-22) GoCN每日新闻(2019-10-22) 1. Go 集成测试:https://www.ardanlabs.com/blog/2019/10/integrat ...

  5. mysql 创建联结

    mysql> select * from user; +------+----------+-----------+ | id | name | address | +------+------ ...

  6. ranger 使用外置的solr

    一.solrcloud部署 1.下载部署 1).下载二进制包 #wget http://mirrors.tuna.tsinghua.edu.cn/apache/lucene/solr/8.3.0/so ...

  7. Atcoder Regular Contest 060 F题第一问答案证明

    一切的开始 令 \(x\) 为字符串,\(p\) 为正整数.如果对于满足 \(0\le i<|x|−p\) 的任何整数 \(i\) 满足 \(x[i]=x[i+p]\),则 \(p\) 称为 \ ...

  8. D3.js的v5版本入门教程(第十章)

    在这一章我们干点有趣的事——让我们上一章绘制的图表动起来,这样岂不是很有意思 为了让图表动起来,我们还是需要以下新的知识点 .attr(xxx) .transition() .attr(xxx),tr ...

  9. Java多线程的Callable, Future, FutureCallback

    Callable可以看成是一个增强版的Runnable, 带返回结果, 需要通过Future或者FutureTask来提交任务或运行线程, 然后通过Future/FutureTask的get方法得到返 ...

  10. [转]白话HTTP短连接中的Session和Token

    我经常想象并怀念三十年前那原始而美好的互联网旧时光, 工作很轻松, 生活很悠闲. 上班的时候偶尔有些HTTP的请求发到我这里, 我简单的看一下, 取出相对应的html文档,图片,发回去就可以了, 然后 ...