1.Quartz串行执行
在Quartz中,作业(Job)默认是以并行方式执行的,这意味着如果调度器(Scheduler)有多个线程可用,并且满足触发条件,那么多个作业可能会同时执行。然而,有时候我们可能希望作业以串行方式执行,即一个接一个地执行,而不是同时执行。
实例
记录每个任务执行间隔
代码
package job;import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;import javax.xml.crypto.Data;
import java.util.Date;public class MyJob implements Job {@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {try {Thread.sleep(2000);System.out.println("excute:"+new Date());} catch (Exception e) {e.printStackTrace();}}
}
package schedule;import job.MyJob;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;public class MySchedule {public static void main(String[] args) {// 创建作业详情JobDetail jobDetail = JobBuilder.newJob(MyJob.class)//作业的类名.withIdentity("myJob", "group1")//作业的身份标识(名称和组名).build();//创建触发器Trigger trigger = TriggerBuilder.newTrigger().withIdentity("myTrigger", "group1")//触发器的身份标识(名称和组名).withSchedule(SimpleScheduleBuilder.simpleSchedule()//设置触发器的调度计划.withIntervalInSeconds(2)//设置作业执行的间隔时间为2秒。.repeatForever())//指定触发器应该无限次地重复执行作业。.build();try {// 创建调度器实例Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();// 将作业和触发器注册到调度器scheduler.scheduleJob(jobDetail, trigger);// 开始调度scheduler.start();} catch (SchedulerException se) {se.printStackTrace();}}
}
执行结果
每个任务最少需要3秒完成,而任务执行间隔为2,说明任务调度是并发执行的
串行执行的两种方法
1.使用单个线程调度器
如果你只有一个线程用于执行作业,那么作业自然会串行执行。你可以通过配置线程池来实现这一点,确保线程池的大小为1。这样,在任何给定时间,只有一个作业能够被执行。
ThreadPoolTaskExecutor threadPool = new ThreadPoolTaskExecutor(); threadPool.setCorePoolSize(1); threadPool.setMaxPoolSize(1); threadPool.setQueueCapacity(1); threadPool.setThreadNamePrefix("Quartz-Executor-"); threadPool.initialize(); SchedulerFactory schedulerFactory = new StdSchedulerFactory(); Scheduler scheduler = schedulerFactory.getScheduler(); scheduler.setThreadPool(threadPool); scheduler.start();
2.使用@DisallowConcurrentExecution注解
package job;import org.quartz.*;import javax.xml.crypto.Data;
import java.util.Date;
@DisallowConcurrentExecution
public class MyJob implements Job {@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {try {Thread.sleep(3000);System.out.println("excute:"+new Date());} catch (Exception e) {e.printStackTrace();}}
}
3.结果
2.JobDataMap数据持久化(持久化到内存中)
实例
计算任务执行次数
代码
package job;import org.quartz.*;import java.util.Date;@DisallowConcurrentExecutionpublic class MyJob2 implements Job {@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {try {JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();jobDataMap.put("count",jobDataMap.getInt("count")+1);System.out.println(jobDataMap.getInt("count")+"-"+new Date());} catch (Exception e) {e.printStackTrace();}}
}
package schedule;import job.MyJob;
import job.MyJob2;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;public class MySchedule2 {public static void main(String[] args) {Integer count=0;// 创建作业详情JobDetail jobDetail = JobBuilder.newJob(MyJob2.class)//作业的类名.withIdentity("myJob", "group1")//作业的身份标识(名称和组名).usingJobData("count", count).build();//创建触发器Trigger trigger = TriggerBuilder.newTrigger().withIdentity("myTrigger", "group1")//触发器的身份标识(名称和组名).withSchedule(SimpleScheduleBuilder.simpleSchedule()//设置触发器的调度计划.withIntervalInSeconds(1)//设置作业执行的间隔时间为2秒。.repeatForever())//指定触发器应该无限次地重复执行作业。.build();try {// 创建调度器实例Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();// 将作业和触发器注册到调度器scheduler.scheduleJob(jobDetail, trigger);// 开始调度scheduler.start();} catch (SchedulerException se) {se.printStackTrace();}}
}
执行结果
原因分析
Quartz的作业在执行时使用的是触发时创建的JobDataMap的一个拷贝,因此作业中对JobDataMap的任何更改都不会影响到原始的JobDataMap,也不会在作业执行结束后保留下来每次任务调度都会使用新的实例。
解决方案
任务类子类添加@PersistJobDataAfterExecution注解,并在任务类中实现Job接口
执行结果
注意此 注解对trigger中的JobDataMap无效