版权声明:本文由吴仙杰创做整理,转载请注明出处:http://www.javashuo.com/article/p-tqlbjvja-ms.htmlhtml
Quartz 定时任务默认都是并发执行的,不会等待上一次任务执行完毕,只要间隔时间到就会执行,若是定时任执行太长,会长时间占用资源,致使其它任务堵塞。java
禁止并发执行的意思并非不能同时执行多个 Job,而是不能并发执行同一个 Job Definition(由 JobDetail 定义),可是能够同时执行多个不一样的 JobDetail,举例说明,咱们有一个 Job 类,叫作 SayHelloJob,并在这个 Job 上加了 @DisallowConcurrentExecution
注解,而后在这个 Job上 定义了不少个 JobDetail,如 sayHelloToJoeJobDetail,sayHelloToMikeJobDetail,那么当 scheduler 启动时,不会并发执行多个 sayHelloToJoeJobDetail 或者 sayHelloToMikeJobDetail,但能够同时执行 sayHelloToJoeJobDetail 跟 sayHelloToMikeJobDetail。shell
Spring 配置文件中加入:segmentfault
<!-- false 表示等上一个任务执行完后再开启新的任务 --> <property name="concurrent" value="false"/>
当不使用 Spring 的时候就须要在 Job 的实现类上加 @DisallowConcurrentExecution
的注解。api
@PersistJobDataAfterExecution
是用在 Job 实现类上,表示一个有状态的任务,意思是当正常执行完 Job 后,JobDataMap 中的数据应该被改动,以被下一次调用时用。并发
注意:当使用 @PersistJobDataAfterExecution
注解时,为了不并发时,存储数据形成混乱,强烈建议把 @DisallowConcurrentExecution
注解也加上。ui
假设定时任务的时间间隔为 3 秒,但 job 执行时间是 10 秒。当设置 @DisallowConcurrentExecution
之后程序会等任务执行完毕后再去执行,不然会在 3 秒时再启动新的线程执行。.net
当设置 @PersistJobDataAfterExecution
时,在执行完 Job 的 execution
方法后保存 JobDataMap 当中固定数据,以便任务在重复执行的时候具备相同的 JobDataMap;在默认状况下也就是没有设置 @PersistJobDataAfterExecution
的时候每一个 job 都拥有独立 JobDataMap。线程
任务类:code
package org.quartz.examples; import org.quartz.*; import java.util.Date; @PersistJobDataAfterExecution @DisallowConcurrentExecution public class TaskJob implements Job { public static final String NUM_EXECUTIONS = "NumExecutions"; public static final String EXECUTION_DELAY = "ExecutionDelay"; /** * 静态变量能够保持工做状态,但没法达到预期效果 */ private static int _staticCounter = 0; /** * Quartz 每次执行做业时都会从新实例化,非静态变量没法保持工做状态 */ private int _counter = 0; /** * 须要一个公共的空构造方法,以便 scheduler 随时实例化 job */ public TaskJob() { } /** * 该方法实现须要执行的任务 */ public void execute(JobExecutionContext context) throws JobExecutionException { System.err.println("---> " + context.getJobDetail().getKey() + " 运行中[" + new Date() + "]"); JobDataMap map = context.getJobDetail().getJobDataMap(); int executeCount = 0; if (map.containsKey(NUM_EXECUTIONS)) { executeCount = map.getInt(NUM_EXECUTIONS); } // 增量计数并将其存储回 JobDataMap,这样能够适当保持工做状态 executeCount++; map.put(NUM_EXECUTIONS, executeCount); // 只要有任务执行都会递增,没法达到预期效果 _staticCounter++; // 本地变量递增长,但实际上没法保持工做状态 _counter++; long delay = 5000L; if (map.containsKey(EXECUTION_DELAY)) { delay = map.getLong(EXECUTION_DELAY); } try { // 模拟一个耗时的 job Thread.sleep(delay); } catch (InterruptedException e) { e.printStackTrace(); } System.err.println(context.getJobDetail().getKey() + " 的静态变量 _staticCounter 为:" + _staticCounter + ",非静态变量 scheduler 为:" + _counter); System.err.println(context.getJobDetail().getKey() + " 完成了(" + executeCount + ")次 <---"); } }
任务调度类:
package org.quartz.examples; import org.quartz.*; import org.quartz.impl.StdSchedulerFactory; import java.util.Date; public class Executer { public void run() throws Exception { // 经过 schedulerFactory 获取一个调度器 SchedulerFactory sf = new StdSchedulerFactory(); Scheduler sched = sf.getScheduler(); // 建立 jobDetail 实例,绑定 Job 实现类 // 指明 job 的名称,所在组的名称,以及绑定 job 类 JobDetail job1 = JobBuilder.newJob(TaskJob.class) .withIdentity("statefulJob1", "group1") // 给定的键-值对添加到 JobDetail 的 JobDataMap 中 .usingJobData(TaskJob.EXECUTION_DELAY, 10000L).build(); // 定义调度触发规则,先当即执行一次,而后每隔 3 秒执行一次 SimpleTrigger trigger = TriggerBuilder.newTrigger() .withIdentity("trigger1", "group1") .startNow() .withSchedule(SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(3) .repeatForever()) .build(); // 把做业和触发器注册到任务调度中 Date firstRunTime = sched.scheduleJob(job1, trigger); System.out.println(job1.getKey() + " 开始运行于:" + firstRunTime + ",重复:" + trigger.getRepeatCount() + " 次,每次间隔 " + trigger.getRepeatInterval() / 1000 + " 秒"); // 任务 job1 方法中拿到的 JobDataMap 的数据是共享的 // 这里要注意一个状况: 就是 JobDataMap 的数据共享只针对一个 job1 任务 // 若是在下面在新增长一个任务 那么他们之间是不共享的,好比下面的 job2 // 建立第二个 JobDetail 实例 JobDetail job2 = JobBuilder.newJob(TaskJob.class) .withIdentity("statefulJob2", "group1") // 给定的键-值对添加到 JobDetail 的 JobDataMap 中 .usingJobData(TaskJob.EXECUTION_DELAY, 10000L) .build(); // 定义调度触发规则,先当即执行一次,而后每隔 3 秒执行一次 trigger = TriggerBuilder.newTrigger() .withIdentity("trigger2", "group1") .startNow() .withSchedule(SimpleScheduleBuilder.simpleSchedule(). withIntervalInSeconds(3) .repeatForever() // 指定失效时的策略 .withMisfireHandlingInstructionNowWithExistingCount()) .build(); // 这个 job2 与 job1 执行的 JobDataMap 不共享 // 把做业和触发器注册到任务调度中 firstRunTime = sched.scheduleJob(job2, trigger); System.out.println(job2.getKey() + " 开始运行于:" + firstRunTime + ",重复:" + trigger.getRepeatCount() + " 次,每次间隔 " + trigger.getRepeatInterval() / 1000 + " 秒"); // 启动计划程序(实际上直到调度器已经启动才会开始运行) sched.start(); // 等待 60 秒,使咱们的 job 有机会执行 Thread.sleep(60000); // 等待做业执行完成时才关闭调度器 sched.shutdown(true); SchedulerMetaData metaData = sched.getMetaData(); System.out.println("一共运行了:" + metaData.getNumberOfJobsExecuted() + " 个任务"); } public static void main(String[] args) throws Exception { Executer example = new Executer(); example.run(); } }
运行结果:
group1.statefulJob1 开始运行于:Wed Apr 19 17:04:22 CST 2017,重复:-1 次,每次间隔 3 秒 group1.statefulJob2 开始运行于:Wed Apr 19 17:04:22 CST 2017,重复:-1 次,每次间隔 3 秒 ---> group1.statefulJob2 运行中[Wed Apr 19 17:04:22 CST 2017] ---> group1.statefulJob1 运行中[Wed Apr 19 17:04:22 CST 2017] group1.statefulJob2 的静态变量 _staticCounter 为:2,非静态变量 scheduler 为:1 group1.statefulJob1 的静态变量 _staticCounter 为:2,非静态变量 scheduler 为:1 group1.statefulJob2 完成了(1)次 <--- group1.statefulJob1 完成了(1)次 <--- ---> group1.statefulJob1 运行中[Wed Apr 19 17:04:32 CST 2017] ---> group1.statefulJob2 运行中[Wed Apr 19 17:04:32 CST 2017] group1.statefulJob1 的静态变量 _staticCounter 为:4,非静态变量 scheduler 为:1 group1.statefulJob1 完成了(2)次 <--- group1.statefulJob2 的静态变量 _staticCounter 为:4,非静态变量 scheduler 为:1 group1.statefulJob2 完成了(2)次 <--- ---> group1.statefulJob1 运行中[Wed Apr 19 17:04:42 CST 2017] ---> group1.statefulJob2 运行中[Wed Apr 19 17:04:42 CST 2017] group1.statefulJob2 的静态变量 _staticCounter 为:6,非静态变量 scheduler 为:1 group1.statefulJob1 的静态变量 _staticCounter 为:6,非静态变量 scheduler 为:1 group1.statefulJob1 完成了(3)次 <--- group1.statefulJob2 完成了(3)次 <--- ---> group1.statefulJob1 运行中[Wed Apr 19 17:04:52 CST 2017] ---> group1.statefulJob2 运行中[Wed Apr 19 17:04:52 CST 2017] group1.statefulJob2 的静态变量 _staticCounter 为:8,非静态变量 scheduler 为:1 group1.statefulJob2 完成了(4)次 <--- group1.statefulJob1 的静态变量 _staticCounter 为:8,非静态变量 scheduler 为:1 group1.statefulJob1 完成了(4)次 <--- ---> group1.statefulJob2 运行中[Wed Apr 19 17:05:02 CST 2017] ---> group1.statefulJob1 运行中[Wed Apr 19 17:05:02 CST 2017] group1.statefulJob2 的静态变量 _staticCounter 为:10,非静态变量 scheduler 为:1 group1.statefulJob1 的静态变量 _staticCounter 为:10,非静态变量 scheduler 为:1 group1.statefulJob2 完成了(5)次 <--- group1.statefulJob1 完成了(5)次 <--- ---> group1.statefulJob1 运行中[Wed Apr 19 17:05:12 CST 2017] ---> group1.statefulJob2 运行中[Wed Apr 19 17:05:12 CST 2017] group1.statefulJob2 的静态变量 _staticCounter 为:12,非静态变量 scheduler 为:1 group1.statefulJob2 完成了(6)次 <--- group1.statefulJob1 的静态变量 _staticCounter 为:12,非静态变量 scheduler 为:1 group1.statefulJob1 完成了(6)次 <--- 一共运行了:12 个任务
PS:本文针对的 Quartz 版本为 Quartz 2.2.3。官方下载地址:Quartz 2.2.3 .tar.gz