Quartz学习, JAVA定时器


 

Quartz学习

  990人阅读   评论(1)   收藏   举报

目录(?)[+]

pom.xml

[html]   view plain copy
  1. <dependency>  
  2.     <groupId>org.quartz-scheduler</groupId>  
  3.     <artifactId>quartz</artifactId>  
  4.     <version>1.8.5</version>  
  5. </dependency>  
使用的1.8.5版本。当前最新的是2.2.0版本。2.2.0版本中jar包中类发生变动。其他参考资料大部分以1.8.5版本为基准,所以使用1.8.5版本。

一、专用词汇

scheduler:
任务调度器
trigger:
触发器,用于定义任务调度时间规则
job:
任务,即被调度的任务
misfire:

错过的,指本来应该被执行但实际没有被执行的任务调度

二、Quartz 任务调度的基本实现原理

核心元素

Quartz 任务调度的核心元素是 scheduler, trigger 和 job,其中 trigger 和 job 是任务调度的元数据, scheduler 是实际执行调度的控制器。

在 Quartz 中,trigger 是用于定义调度时间的元素,即按照什么时间规则去执行任务。Quartz 中主要提供了四种类型的 trigger:SimpleTrigger,CronTirgger,DateIntervalTrigger,和 NthIncludedDayTrigger。这四种 trigger 可以满足企业应用中的绝大部分需求。我们将在企业应用一节中进一步讨论四种 trigger 的功能。


在 Quartz 中,job 用于表示被调度的任务。主要有两种类型的 job:无状态的(stateless)和有状态的(stateful)。对于同一个 trigger 来说,有状态的 job 不能被并行执行,只有上一次触发的任务被执行完之后,才能触发下一次执行。Job 主要有两种属性:volatility 和 durability,其中 volatility 表示任务是否被持久化到数据库存储,而 durability 表示在没有 trigger 关联的时候任务是否被保留。两者都是在值为 true 的时候任务被持久化或保留。一个 job 可以被多个 trigger 关联,但是一个 trigger 只能关联一个 job。

在 Quartz 中, scheduler 由 scheduler 工厂创建:DirectSchedulerFactory 或者 StdSchedulerFactory(STD:standard标准的意思)。 第二种工厂 StdSchedulerFactory 使用较多,因为 DirectSchedulerFactory 使用起来不够方便,需要作许多详细的手工编码设置。 Scheduler 主要有三种:RemoteMBeanScheduler, RemoteScheduler 和 StdScheduler。本文以最常用的 StdScheduler 为例讲解。这也是笔者在项目中所使用的 scheduler 类。


Quartz 核心元素之间的关系如下图所示:

三、代码示例

1、SimpleTrigger:从startTime时间点开始,每隔repeatInterval时间间隔,执行job一次,共执行repeatCount次

[java]   view plain copy
  1. public class TestJob implements Job {  
  2.   
  3.     public void execute(JobExecutionContext arg0) throws JobExecutionException {  
  4.         System.out.println("执行Job");  
  5.     }  
  6. }  

[java]   view plain copy
  1. private static void test01() {  
  2.     try {  
  3.         /* 通过SchedulerFactory来获取一个调度器;STD:standard标准的意思 */  
  4.         Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();  
  5.           
  6.         /* 作业、任务 */  
  7.         JobDetail jobDetail = new JobDetail("testJobName01""testJobGroup", TestJob.class);  
  8.           
  9.         /* 触发器 */  
  10.         SimpleTrigger trigger = new SimpleTrigger("SimpleTriggerName01""SimpleTriggerGroup");  
  11.         /* 启动时间 */  
  12.         trigger.setStartTime(new Date());  
  13.         /* 设置作业执行间隔 毫秒 */  
  14.         trigger.setRepeatInterval(1000);  
  15.         /* 设置作业执行次数 */  
  16.         trigger.setRepeatCount(10);  
  17.   
  18.         scheduler.scheduleJob(jobDetail, trigger);  
  19.         scheduler.start();  
  20.     } catch (SchedulerException e) {  
  21.         e.printStackTrace();  
  22.     }  
  23. }  

2、DateIntervalTrigger:从startTime时间点开始,每隔repeatInterval时间间隔(间隔单位IntervalUnit),执行job一次

[java]   view plain copy
  1. private static void test02() {  
  2.     try {  
  3.         /* 通过SchedulerFactory来获取一个调度器;STD:standard标准的意思 */  
  4.         Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();  
  5.           
  6.         /* 作业、任务 */  
  7.         JobDetail jobDetail = new JobDetail("testJobName01""testJobGroup", TestJob.class);  
  8.           
  9.         /* 触发器 */  
  10.         DateIntervalTrigger trigger = new DateIntervalTrigger();  
  11.         trigger.setName("testJobName02");  
  12.         /* 启动时间 */  
  13.         trigger.setStartTime(new Date());  
  14.         /* 间隔单位(秒为单位) */  
  15.         trigger.setRepeatIntervalUnit(IntervalUnit.SECOND);  
  16.         /* 时间间隔 */  
  17.         trigger.setRepeatInterval(3);  
  18.   
  19.         scheduler.scheduleJob(jobDetail, trigger);  
  20.         scheduler.start();  
  21.     } catch (SchedulerException e) {  
  22.         e.printStackTrace();  
  23.     }  
  24. }  

3、CronTrigger

CronTrigger 能够提供比 SimpleTrigger 更有具体实际意义的调度方案,调度规则基于 Cron 表达式,CronTrigger 支持日历相关的重复时间间隔(比如每月第一个周一执行),而不是简单的周期时间间隔。因此,相对于SimpleTrigger而言,CronTrigger在使用上也要复杂一些。

Cron表达式时间字段

位置

时间域名

允许值

允许的特殊字符

1

0-59

, - * /

2

分钟

0-59

, - * /

3

小时

0-23

, - * /

4

日期

1-31

, - * ? / L W C

5

月份

1-12

, - * /

6

星期

1-7

, - * ? / L C #

7

年(可选)

空值1970-2099

, - * /

Cron表达式的时间字段除允许设置数值外,还可使用一些特殊的字符,提供列表、范围、通配符等功能,细说如下:

●星号(*):可用在所有字段中,表示对应时间域的每一个时刻,例如,*在分钟字段时,表示“每分钟”;

●问号(?):该字符只在日期和星期字段中使用,它通常指定为“无意义的值”,相当于点位符;

“月份中的日期”和“星期中的日期”这两个元素是互斥的,因此应该通过设置一个问号(?)来表明你不想设置的那个字段

●减号(-):表达一个范围,如在小时字段中使用“10-12”,则表示从10到12点,即10,11,12;

●逗号(,):表达一个列表值,如在星期字段中使用“MON,WED,FRI”,则表示星期一,星期三和星期五;

●斜杠(/):x/y表达一个等步长序列,x为起始值,y为增量步长值。如在分钟字段中使用0/15,则表示为0,15,30和45秒,而5/15在分钟字段中表示5,20,35,50,你也可以使用*/y,它等同于0/y;

●L:该字符只在日期和星期字段中使用,代表“Last”的意思,但它在两个字段中意思不同。L在日期字段中,表示这个月份的最后一天,如一月的31号,非闰年二月的28号;如果L用在星期中,则表示星期六,等同于7。但是,如果L出现在星期字段里,而且在前面有一个数值X,则表示“这个月的最后X天”,例如,6L表示该月的最后星期五;

●W:该字符只能出现在日期字段里,是对前导日期的修饰,表示离该日期最近的工作日。例如15W表示离该月15号最近的工作日,如果该月15号是星期六,则匹配14号星期五;如果15日是星期日,则匹配16号星期一;如果15号是星期二,那结果就是15号星期二。但必须注意关联的匹配日期不能够跨月,如你指定1W,如果1号是星期六,结果匹配的是3号星期一,而非上个月最后的那天。W字符串只能指定单一日期,而不能指定日期范围;

●LW组合:在日期字段可以组合使用LW,它的意思是当月的最后一个工作日;

●井号(#):该字符只能在星期字段中使用,表示当月某个工作日。如6#3表示当月的第三个星期五(6表示星期五,#3表示当前的第三个),而4#5表示当月的第五个星期三,假设当月没有第五个星期三,忽略不触发;

● C:该字符只在日期和星期字段中使用,代表“Calendar”的意思。它的意思是计划所关联的日期,如果日期没有被关联,则相当于日历中所有日期。例如5C在日期字段中就相当于日历5日以后的第一天。1C在星期字段中相当于星期日后的第一天。

Cron表达式对特殊字符的大小写不敏感,对代表星期的缩写英文大小写也不敏感。

Cron表示式示例

表示式

说明

"0 0 12 * * ? "

每天12点运行

"0 15 10 ? * *"

每天10:15运行

"0 15 10 * * ?"

每天10:15运行

"0 15 10 * * ? *"

每天10:15运行

"0 15 10 * * ? 2008"

在2008年的每天10:15运行

"0 * 14 * * ?"

每天14点到15点之间每分钟运行一次,开始于14:00,结束于14:59。

"0 0/5 14 * * ?"

每天14点到15点每5分钟运行一次,开始于14:00,结束于14:55。

"0 0/5 14,18 * * ?"

每天14点到15点每5分钟运行一次,此外每天18点到19点每5钟也运行一次。

"0 0-5 14 * * ?"

每天14:00点到14:05,每分钟运行一次。

"0 10,44 14 ? 3 WED"

3月每周三的14:10分到14:44,每分钟运行一次。

"0 15 10 ? * MON-FRI"

每周一,二,三,四,五的10:15分运行。

"0 15 10 15 * ?"

每月15日10:15分运行。

"0 15 10 L * ?"

每月最后一天10:15分运行。

"0 15 10 ? * 6L"

每月最后一个星期五10:15分运行。

"0 15 10 ? * 6L 2007-2009"

在2007,2008,2009年每个月的最后一个星期五的10:15分运行。

"0 15 10 ? * 6#3"

每月第三个星期五的10:15分运行。

示例

[java]   view plain copy
  1. private static void test03() {  
  2.     try {  
  3.         /* 通过SchedulerFactory来获取一个调度器;STD:standard标准的意思 */  
  4.         Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();  
  5.           
  6.         /* 作业、任务 */  
  7.         JobDetail jobDetail = new JobDetail("testJobName01""testJobGroup", TestJob.class);  
  8.           
  9.         CronTrigger trigger = new CronTrigger("testJobName03");  
  10.         /* Cron表达式制定调度规则 */  
  11.         try {  
  12.             trigger.setCronExpression(new CronExpression("0/5 * * * * ?")); // 每隔5秒钟执行一次  
  13.         } catch (ParseException e) {  
  14.             e.printStackTrace();  
  15.         }  
  16.   
  17.         scheduler.scheduleJob(jobDetail, trigger);  
  18.         scheduler.start();  
  19.     } catch (SchedulerException e) {  
  20.         e.printStackTrace();  
  21.     }  
  22. }  

4、Scheduler.shutDown()

[java]   view plain copy
  1. try {  
  2.     /* 当scheduler不为空,且运行状态,执行shutdown */  
  3.     if(scheduler != null && scheduler.isStarted())  
  4.         scheduler.shutdown();  
  5. catch (SchedulerException e) {  
  6.     e.printStackTrace();  
  7. }  
source code:可执行等待job执行完成后再shutdown

[java]   view plain copy
  1. /** 
  2. * <p> 
  3. * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>. 
  4. * </p> 
  5. */  
  6. public void shutdown() {  
  7. sched.shutdown();  
  8. }  
  9.   
  10. /** 
  11. * <p> 
  12. * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>. 
  13. * </p> 
  14. */  
  15. public void shutdown(boolean waitForJobsToComplete) {  
  16. sched.shutdown(waitForJobsToComplete);  
  17. }  

四、其他示例

(1)不可以针对一个trigger绑定多个job

代码:

[java]   view plain copy
  1. private static void oneTriggerTwoJob() {  
  2.     try {  
  3.         /* 通过SchedulerFactory来获取一个调度器;STD:standard标准的意思 */  
  4.         Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();  
  5.   
  6.         /* 作业、任务 */  
  7.         JobDetail jobDetail1 = new JobDetail("testJobName01""testJobGroup", TestJob.class);  
  8.         JobDetail jobDetail2 = new JobDetail("testJobName02""testJobGroup", TestJob2.class);  
  9.   
  10.         /* 触发器 */  
  11.         SimpleTrigger trigger = new SimpleTrigger("SimpleTriggerName01""SimpleTriggerGroup");  
  12.         ......  
  13.   
  14.         scheduler.scheduleJob(jobDetail1, trigger);  
  15.         scheduler.scheduleJob(jobDetail2, trigger);  
  16.         scheduler.start();  
  17.     } catch (SchedulerException e) {  
  18.         e.printStackTrace();  
  19.     }  
  20. }  
运行后会抛出异常:

[plain]   view plain copy
  1. <span style="color:#FF0000">org.quartz.SchedulerException: Trigger does not reference given job!  
  2.     at org.quartz.core.QuartzScheduler.scheduleJob(QuartzScheduler.java:778)  
  3.     at org.quartz.impl.StdScheduler.scheduleJob(StdScheduler.java:243)</span>  
(2)scheduler关联多个trigger和job

[java]   view plain copy
  1. scheduler.scheduleJob(jobDetail1, trigger1);  
  2. scheduler.scheduleJob(jobDetail2, trigger2);  
  3. scheduler.start();  

(3)TriggerUtils工具类

[java]   view plain copy
  1. Trigger trigger = TriggerUtils.makeHourlyTrigger(1);  

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值