Quartz是一个特性丰富的开源的任务调度开发库,它可以很方便的集成到你的应用程序中。在Quartz中,当一个持久的触发器因为调度器被关闭或者线程池中没有可用的线程而错过了激活时间时,就会发生激活失败(misfire)。那么,我们需要明确2个问题:如何判定激活失败;如何处理激活失败。

一、激活失败判定

quartz.properties配置文件中有一个属性是misfireThreshold(单位为毫秒),用来指定调度引擎设置触发器超时的"临界值"。也就是说Quartz对于任务的超时是有容忍度的,超过了这个容忍度才会判定misfire。比如说,某触发器设置为,10:15首次激活,然后每隔3秒激活一次,无限次重复。然而该任务每次运行需要10秒钟的时间。可见,每次任务的执行都会超时,那么究竟是否会引起misfire,就取决于misfireThreshold的值了。以第二次任务来说,它的运行时间已经比预定晚了7秒,那么如果misfireThreshold>7000,说明该偏差可容忍,则不算misfire,该任务立刻执行;如果misfireThreshold<=7000,则判定为misfire,根据相关配置策略进行处理。

注意,任务的延迟是有累计的。在前面的例子中,假设misfireThreshold设置为60000,即60秒。那么每次任务的延迟量即是否misfire计算如下:

任务编号

预定运行时刻

实际运行时刻

延迟量(秒)

备注

1

10:15

10:15

0

2

10:18

10:25

7

3

10:21

10:35

14

4

10:24

10:45

21

5

10:27

10:55

28

6

10:30

11:05

35

7

10:33

11:15

42

8

10:36

11:25

49

9

10:39

11:35

56

10

10:42

11:45

63

misfire

从表中可以看到,每一次任务执行都会带来7秒的延迟量,该延迟量不断被与misfireThreshold比较,直到达到该值后,在11:45分发生misfire。那么在11:45第10次任务会不会准时执行呢?答案是不一定,取决于配置。

二、激活失败处理

激活失败指令(Misfire Instructions)是触发器的一个重要属性,它指定了misfire发生时调度器应当如何处理。所有类型的触发器都有一个默认的指令,叫做Trigger.MISFIRE_INSTRUCTION_SMART_POLICY,但是这个这个“聪明策略”对于不同类型的触发器其具体行为是不同的。对于SimpleTrigger,这个“聪明策略”将根据触发器实例的状态和配置来决定其行为。具体如下[]:

如果Repeat Count=0:

instruction selected = MISFIRE_INSTRUCTION_FIRE_NOW;

如果Repeat Count=REPEAT_INDEFINITELY:

instruction selected = MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT;

如果Repeat Count>0:

instruction selected = MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT;

下面解释SimpleTrigger常见策略:

MISFIRE_INSTRUCTION_FIRE_NOW

立刻执行。对于不会重复执行的任务,这是默认的处理策略。

MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT

NEXT指以现在为基准,以repeat interval为周期,延时到下一个激活点执行。WITH_REMAINING_COUNT指超时期内错过的执行机会作废。因此该策略的含义是,在下一个激活点执行,且超时期内错过的执行机会作废。

MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_COUNT

立即执行,且超时期内错过的执行机会作废。

MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT

WITH_EXISTING_COUNT指,根据已设置的repeat count进行执行。也就是说错过的执行机会不作废,保证实际执行次数满足设置。因此本策略的含义是,在下一个激活点执行,并重复到指定的次数。

MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_COUNT

立即执行,并重复到指定的次数。

MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY

忽略所有的超时状态,按照触发器的策略执行。

对于CronTrigger,该“聪明策略”默认选择MISFIRE_INSTRUCTION_FIRE_ONCE_NOW以指导其行为。

下面解释CronTrigger常见策略:

MISFIRE_INSTRUCTION_FIRE_ONCE_NOW

立刻执行一次,然后就按照正常的计划执行。

MISFIRE_INSTRUCTION_DO_NOTHING

目前不执行,然后就按照正常的计划执行。这意味着如果下次执行时间超过了end time,实际上就没有执行机会了。

三、示例程序1

=====代码=====

JobDetail job1 = newJob(StatefulDumbJob.class).withIdentity("statefulJob1", "group1")
.usingJobData(StatefulDumbJob.EXECUTION_DELAY, 10000L).build(); SimpleTrigger trigger1 = newTrigger().withIdentity("trigger1", "group1").startAt(startTime)
.withSchedule(simpleSchedule().withIntervalInSeconds(3).repeatForever()).build(); Date ft1 = sched.scheduleJob(job1, trigger1);
log.info(job1.getKey() + " will run at: " + ft1 + " and repeat: " + trigger1.getRepeatCount() + " times, every "
+ trigger1.getRepeatInterval() / 1000 + " seconds");

=====代码=====

misfireThreshold设置为60000。

分析:

各任务的延迟量如下表所示:

任务编号

预定运行时刻

实际运行时刻

延迟量(秒)

备注

1

16:15:45

16:15:45

0

2

16:15:48

16:15:55

7

3

16:15:51

16:16:05

14

4

16:15:54

16:16:15

21

5

16:15:57

16:16:25

28

6

16:16:00

16:16:35

35

7

16:16:03

16:16:45

42

8

16:16:06

16:16:55

49

9

16:16:09

16:17:05

56

无

16:16:12

16:17:15

63

misfire

10

16:17:18

16:17:18

0

11

16:17:21

16:17:28

7

在16:17:15发生misfire。因为Repeat Count=REPEAT_INDEFINITELY,所以smart policy选择的策略是MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT。因此,延时3秒后,在16:17:18第10次任务被执行,延迟量清零。当然,程序会一直这样循环下去。

程序输出:

---group1.statefulJob1 executing.[Fri Feb 19 16:15:45 CST 2016]

-group1.statefulJob1 complete (1).

---group1.statefulJob1 executing.[Fri Feb 19 16:15:55 CST 2016]

-group1.statefulJob1 complete (2).

---group1.statefulJob1 executing.[Fri Feb 19 16:16:05 CST 2016]

-group1.statefulJob1 complete (3).

---group1.statefulJob1 executing.[Fri Feb 19 16:16:15 CST 2016]

-group1.statefulJob1 complete (4).

---group1.statefulJob1 executing.[Fri Feb 19 16:16:25 CST 2016]

-group1.statefulJob1 complete (5).

---group1.statefulJob1 executing.[Fri Feb 19 16:16:35 CST 2016]

-group1.statefulJob1 complete (6).

---group1.statefulJob1 executing.[Fri Feb 19 16:16:45 CST 2016]

-group1.statefulJob1 complete (7).

---group1.statefulJob1 executing.[Fri Feb 19 16:16:55 CST 2016]

-group1.statefulJob1 complete (8).

---group1.statefulJob1 executing.[Fri Feb 19 16:17:05 CST 2016]

-group1.statefulJob1 complete (9).

---group1.statefulJob1 executing.[Fri Feb 19 16:17:18 CST 2016]

-group1.statefulJob1 complete (10).

四、示例程序2

=====代码=====

JobDetail job2 = newJob(StatefulDumbJob.class).withIdentity("statefulJob2", "group1")
.usingJobData(StatefulDumbJob.EXECUTION_DELAY, 10000L).build(); SimpleTrigger trigger2 = newTrigger()
.withIdentity("trigger2", "group1")
.startAt(startTime)
.withSchedule(simpleSchedule().withIntervalInSeconds(3).repeatForever()
.withMisfireHandlingInstructionNowWithExistingCount()) // set misfire instructions
.build(); Date ft2 = sched.scheduleJob(job2, trigger2);
log.info(job2.getKey() + " will run at: " + ft2 + " and repeat: " + trigger2.getRepeatCount() + " times, every "
+ trigger2.getRepeatInterval() / 1000 + " seconds");

=====代码=====

misfireThreshold设置为60000。

分析:

示例2与示例1的区别在于,触发器指定了激活失败指令为MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_COUNT。

各任务的延迟量如下表所示:

任务编号

预定运行时刻

实际运行时刻

延迟量(秒)

备注

1

17:05:15

17:05:15

0

2

17:05:18

17:05:25

7

3

17:05:21

17:05:35

14

4

17:05:24

17:05:45

21

5

17:05:27

17:05:55

28

6

17:05:30

17:06:05

35

7

17:05:33

17:06:15

42

8

17:05:36

17:06:25

49

9

17:05:39

17:06:35

56

无

17:05:42

17:06:45

63

misfire

10

17:06:45

17:06:45

0

11

17:05:48

17:06:55

7

在17:06:45发生misfire。根据其激活失败指令,任务10在该时刻被立即执行,延迟量清零。然后,程序继续如此循环下去。

程序输出:

---group1.statefulJob2 executing.[Fri Feb 19 17:05:15 CST 2016]
-group1.statefulJob2 complete (1).
---group1.statefulJob2 executing.[Fri Feb 19 17:05:25 CST 2016]
-group1.statefulJob2 complete (2).
---group1.statefulJob2 executing.[Fri Feb 19 17:05:35 CST 2016]
-group1.statefulJob2 complete (3).
---group1.statefulJob2 executing.[Fri Feb 19 17:05:45 CST 2016]
-group1.statefulJob2 complete (4).
---group1.statefulJob2 executing.[Fri Feb 19 17:05:55 CST 2016]
-group1.statefulJob2 complete (5).
---group1.statefulJob2 executing.[Fri Feb 19 17:06:05 CST 2016]
-group1.statefulJob2 complete (6).
---group1.statefulJob2 executing.[Fri Feb 19 17:06:15 CST 2016]
-group1.statefulJob2 complete (7).
---group1.statefulJob2 executing.[Fri Feb 19 17:06:25 CST 2016]
-group1.statefulJob2 complete (8).
---group1.statefulJob2 executing.[Fri Feb 19 17:06:35 CST 2016]
-group1.statefulJob2 complete (9).
---group1.statefulJob2 executing.[Fri Feb 19 17:06:45 CST 2016]
-group1.statefulJob2 complete (10).
---group1.statefulJob2 executing.[Fri Feb 19 17:06:55 CST 2016]
-group1.statefulJob2 complete (11).

Quartz的misfire处理机制分析的更多相关文章

  1. quartz群调查调度机制和源代码分析

    pageId=85056282#quartz集群调度机制调研及源代码分析-quartz2.2.1集群调度机制调研及源代码分析" style="color:rgb(59,115,17 ...

  2. Linux mips64r2 PCI中断路由机制分析

    Linux mips64r2 PCI中断路由机制分析 本文主要分析mips64r2 PCI设备中断路由原理和irq号分配实现方法,并尝试回答如下问题: PCI设备驱动中断注册(request_irq) ...

  3. IOS Table中Cell的重用reuse机制分析

    IOS Table中Cell的重用reuse机制分析 技术交流新QQ群:414971585 创建UITableViewController子类的实例后,IDE生成的代码中有如下段落: - (UITab ...

  4. 您还有心跳吗?超时机制分析(java)

    注:本人是原作者,首发于并发编程网(您还有心跳吗?超时机制分析),此文结合那里的留言作了一些修改. 问题描述 在C/S模式中,有时我们会长时间保持一个连接,以避免频繁地建立连接,但同时,一般会有一个超 ...

  5. Java 类反射机制分析

    Java 类反射机制分析 一.反射的概念及在Java中的类反射 反射主要是指程序可以访问.检测和修改它本身状态或行为的一种能力.在计算机科学领域,反射是一类应用,它们能够自描述和自控制.这类应用通过某 ...

  6. Linux信号(signal) 机制分析

    Linux信号(signal) 机制分析 [摘要]本文分析了Linux内核对于信号的实现机制和应用层的相关处理.首先介绍了软中断信号的本质及信号的两种不同分类方法尤其是不可靠信号的原理.接着分析了内核 ...

  7. Java 动态代理机制分析及扩展

    Java 动态代理机制分析及扩展,第 1 部分 王 忠平, 软件工程师, IBM 何 平, 软件工程师, IBM 简介: 本文通过分析 Java 动态代理的机制和特点,解读动态代理类的源代码,并且模拟 ...

  8. Quartz的misfire特性

    Quartz的misfire特性 只有一个线程.多个job 第一个job产生misfire(executeTime>Interval) 且是repeatForever 那么只会运行第一个job, ...

  9. Android内存机制分析1——了解Android堆和栈

    //----------------------------------------------------------------------------------- Android内存机制分析1 ...

随机推荐

  1. python编程基础知识—列表(二)

    3操作列表 3.1 遍历整个列表 使用for循环 cars = ['bmw','audi','toyota','Jeep'] for i in cars: print(i) bmw audi toyo ...

  2. QTextEdit控件使用

    QTextEdit控件使用 QTextEdit *mpContentTextEdit = new QTextEdit(this); //设置占位符文本 mpContentTextEdit->se ...

  3. testng相关的Annotation注释方法,

    2 - Annotation这里是TestNG中用到的annotation的快速预览,还有它们的属性. @BeforeSuite: 被注释的方法将在所有测试运行前运行,方法将只运行一次@AfterSu ...

  4. 【Java学习笔记之二十二】解析接口在Java继承中的用法及实例分析

    一.定义 Java接口(Interface),是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为( ...

  5. 【前端】向blog或网站中添加语法高亮显示代码方法总结

    向blog或网站中添加语法高亮显示的代码方法总结 文章目录 预备知识 目标 第一类方法:嵌入 第二类方法:外部引用 第三类方法:忽略HTML和PHP 最近在写代码时遇到一个问题,就是如何让代码像在ID ...

  6. destoon源码分析一

    #0x01 先记录一些之前模糊的小知识点,补充一下 set_magic_quotes_runtime() -- 设置magic_quotes_runtime配置激活状态(php 5.3 被弃用,php ...

  7. unity slua整合帅气的lua-pb解析protobuf

    了解到lua的一个protobuf库,接口帅气,比之前用过的一些lua protobuf库要好很多,深得我心.而且能保持更新,比其他库几年没更新要放心. lua-pb动态解析protobuf协议,无需 ...

  8. C# 逆变与协变

    该文章中使用了较多的 委托delegate和Lambda表达式,如果你并不熟悉这些,请查看我的文章<委托与匿名委托>.<匿名委托与Lambda表达式>以便帮你建立完整的知识体系 ...

  9. BestCoder Round #32_1001 以及 hdu 5182

    http://bestcoder.hdu.edu.cn/contests/contest_chineseproblem.php?cid=570&pid=1001 http://acm.hdu. ...

  10. Java的常用操作符

    操作符用于接受一个或多个参数,并生成一个新的值.加号和一元的正号(+).减号和一元的负号(一).乘号(*).除号(/)以及赋值号(=)的用法和大多数编程语言都类似. 操作符作用于操作数,生成一个新值. ...