#同一任务并发执行与数据共享
@(springboot)[quartz]
[TOC]
1. 禁止同一个 JobDetail 中的多个实例并发执行
Quartz 定时任务默认都是并发执行的,不会等待上一次任务执行完毕,只要间隔时间到就会执行。
注 同一任务的含义指同一个JobKey 。
1.1 方法一、使用 xml
Spring 配置文件中加入:
1 2 3 4 5 6 7 8
| <bean id="resultJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="resultJob"></property>
<property name="targetMethod" value="createDemEmps"></property>
<property name="concurrent" value="false" /> </bean>
|
1.2 方法二、使用注解
当不使用 Spring 的时候,只需要在 Job 的实现类上加 @DisallowConcurrentExecution 的注解。
1 2 3 4 5 6 7 8 9
| @DisallowConcurrentExecution public class DaemonExecutionSchedule implements Job{ private Logger logger = LoggerFactory.getLogger(this.getClass());
@Override public void execute(JobExecutionContext context) throws JobExecutionException { ... } }
|
2. 同一个 JobDetail 中多个实例的数据共享
@PersistJobDataAfterExecution 是用在 Job 实现类上,表示一个有状态的任务,意思是当正常执行完 Job 后,JobDataMap 中的数据应该被改动,以被下一次调用时用。
注意:当使用 @PersistJobDataAfterExecution 注解时,为了避免并发时,存储数据造成混乱,强烈建议把 @DisallowConcurrentExecution 注解也加上。
3. 示例
假设定时任务的时间间隔为 3 秒,但 job 执行时间是 10 秒。当设置 @DisallowConcurrentExecution 以后程序会等任务执行完毕后再去执行。
当设置 @PersistJobDataAfterExecution 时,在执行完 Job 的 execution 方法后保存 JobDataMap 当中固定数据,以便任务在重复执行的时候具有相同的 JobDataMap;在默认情况下也就是没有设置 @PersistJobDataAfterExecution 的时候每个 job 都拥有独立 JobDataMap。
任务类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| 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;
private int _counter = 0;
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); }
executeCount++; map.put(NUM_EXECUTIONS, executeCount);
_staticCounter++;
_counter++;
long delay = 5000L; if (map.containsKey(EXECUTION_DELAY)) { delay = map.getLong(EXECUTION_DELAY); }
try { 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 + ")次 <---"); } }
|
任务调度类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
| 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 sf = new StdSchedulerFactory(); Scheduler sched = sf.getScheduler();
JobDetail job1 = JobBuilder.newJob(TaskJob.class) .withIdentity("statefulJob1", "group1") .usingJobData(TaskJob.EXECUTION_DELAY, 10000L).build();
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 + " 秒");
JobDetail job2 = JobBuilder.newJob(TaskJob.class) .withIdentity("statefulJob2", "group1") .usingJobData(TaskJob.EXECUTION_DELAY, 10000L) .build();
trigger = TriggerBuilder.newTrigger() .withIdentity("trigger2", "group1") .startNow() .withSchedule(SimpleScheduleBuilder.simpleSchedule(). withIntervalInSeconds(3) .repeatForever() .withMisfireHandlingInstructionNowWithExistingCount()) .build();
firstRunTime = sched.scheduleJob(job2, trigger); System.out.println(job2.getKey() + " 开始运行于:" + firstRunTime + ",重复:" + trigger.getRepeatCount() + " 次,每次间隔 " + trigger.getRepeatInterval() / 1000 + " 秒");
sched.start();
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(); } }
|
运行结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| 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 个任务