Quartz定时任务默认都是并发执行的,不会等待上一次任务执行完毕,只要间隔时间到就会执行, 如果定时任执行太长,会长时间占用资源,导致其它任务堵塞。
在Spring中这时需要设置concurrent的值为false, 禁止并发执行。
<property name="concurrent" value="true" />
当不使用spring的时候就需要在Job的实现类上加@DisallowConcurrentExecution的注释
@DisallowConcurrentExecution 禁止并发执行多个相同定义的JobDetail, 这个注解是加在Job类上的, 但意思并不是不能同时执行多个Job, 而是不能并发执行同一个Job Definition(由JobDetail定义),但是可以同时执行多个不同的JobDetail, 也就是说一个JobKey对应的JobDetail实例不会进行并发执行,举例说明,我们有一个Job类,叫做QuartzJob,QuartzJob1,QuartzJob2他们都是实现了Job接口,并在这些类上加了这个注解@DisallowConcurrentExecution, 然后在这个Job上定义了很多个JobDetail, QuartzJobJobDetail,QuartzJob1JobDetail,QuartzJob2JobDetail,那么当scheduler启动时, 不会并发执行多个QuartzJobJobDetail或者QuartzJob1JobDetail以及QuartzJob2JobDetail,而是QuartzJob类下QuartzJobJobDetail的任务调度同步执行,其它几个(QuartzJob1JobDetail,QuartzJob2JobDetail的任务调度下的)一样,但是可以同时执行QuartzJobJobDetail,QuartzJob1JobDetail,QuartzJob2JobDetail
- @PersistJobDataAfterExecution 同样, 也是加在Job上,表示当正常执行完Job后, JobDataMap中的数据应该被改动, 以被下一次调用时用。(注意:@PersistJobDataAfterExecution是持久化JobDetail中的JobDataMap,对Trigger中的JobDataMap无效)
- 当使用@PersistJobDataAfterExecution 注解时, 为了避免并发时, 存储数据造成混乱, 强烈建议把@DisallowConcurrentExecution注解也加上。
@DisallowConcurrentExecution
- 此标记用在实现Job的类上面,意思是不允许并发执行,按照我之前的理解是 不允许调度框架在同一时刻调用Job类,后来经过测试发现并不是这样,而是Job(任务)的执行时间(比如需要10秒)大于任务的时间间隔【Interval(5秒)】,那么默认情况下,调度框架为了能让 任务按照我们预定的时间间隔执行,会马上启用新的线程执行任务。否则的话会等待任务执行完毕以后 再重新执行!(这样会导致任务的执行不是按照我们预先定义的时间间隔执行)
- 测试代码,这是官方提供的例子。设定的时间间隔为3秒,但job执行时间是5秒,设置@DisallowConcurrentExecution以后程序会等任务执行完毕以后再去执行,否则会在3秒时再启用新的线程执行
代码如下:
/**
* 该类将会被org.springframework.scheduling.quartz.SpringBeanJobFactory 实例化
* 并使@Autowired 生效
*/
@Slf4j
@Setter
@DisallowConcurrentExecution
public class QuartzJob implements Job {
@Autowired
private ApplicationEventPublisher publisher;
/**
* 任务调度参数key
*/
public static final String JOB_PARAM_KEY = "JOB_PARAM_KEY";
private String dd;
@Override
@SneakyThrows
public void execute(JobExecutionContext jobExecutionContext) {
TreeNode o = (TreeNode) jobExecutionContext.getMergedJobDataMap().get(JOB_PARAM_KEY);
JobDataMap mergedJobDataMap = jobExecutionContext.getMergedJobDataMap();
JobDataMap jobDataMap = jobExecutionContext.getTrigger().getJobDataMap();
JobDataMap jobDataMap1 = jobExecutionContext.getJobDetail().getJobDataMap();
System.out.println("QuartzJob execute:" + SystemClock.nowDate());
PerUsers user = new PerUsers();
System.out.println("user hashCode: " + user.hashCode());
System.out.println("user identityHashCode: " + System.identityHashCode(user));
/**这个任务你不知道要执行多久,而我们这个多线程的特性间隔时间一到,
* 前面一个任务还没有执行完,那么它又会启动一个任务去执行,那如果时同一个实例的话就会存在并发问题
*
*/
System.out.println(System.identityHashCode(jobExecutionContext.getJobDetail()));
System.out.println(System.identityHashCode(jobExecutionContext.getJobInstance()));
//由此证明任务调度都是异步进行的 互不影响
try {
Thread.sleep(3000);
System.out.println("user = ");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
结论:经过代码测试在没有加@DisallowConcurrentExecution注解之前是没有休眠3秒进行下一个任务它们互不干扰,在QuartzJob 类加上@DisallowConcurrentExecution注解以后,中间会休息3秒以后执行下一个任务调度,由此可见,QuartzJob 类下的任务调度全部同步执行