在Spring Boot定时任务spring-boot-starter-quartz配置运行及测试这篇文章中我们简单介绍了Spring Boot中如何实现定时任务,但是有个问题,当任务的执行时长超过定时任务触发的间隔时,就会导致两个或多个任务并发在执行,如果我们不希望定时任务并发执行可以通过@DisallowConcurrentExecution注解来禁止并发。
下面通过简单的代码来演示定时任务并发和串行的情况,关于定时任务的配置先看这篇文章Spring Boot定时任务spring-boot-starter-quartz配置运行及测试
配置
将定时任务间隔设置成3秒
@Configuration
public class CustomizeScheduleConfigTask {
/**
* 定时任务
* @return
*/
@Bean
public JobDetail testJobDetail() {
return JobBuilder.newJob(TestJobBean.class)
.withIdentity("testJobDetail")
.storeDurably()
.build();
}
/**
* 触发器,每间隔一段时间触发定时任务
* @param jobDetail 具体执行的定时任务
* @return
*/
@Bean
public Trigger testJobTrigger(@Qualifier("testJobDetail") JobDetail jobDetail) {
ScheduleBuilder scheduleBuilder = SimpleScheduleBuilder
.simpleSchedule()
.withIntervalInSeconds(3) // 定时任务间隔时间
.repeatForever(); // 触发器无限循环触发
return TriggerBuilder.newTrigger()
.forJob(jobDetail)
.withIdentity("testJobTrigger")
.withSchedule(scheduleBuilder)
.build();
}
}
并发
定时任务默认就是并发的
我们通过Thread.sleep()让任务执行时间为6秒,超过定时任务触发间隔的3秒,这样就可以观察到并发
@Service
public class TestJobBean extends QuartzJobBean {
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext) {
System.out.println("TestJobBean 开始:::" + Thread.currentThread().getName() + ":::" + SimpleDateFormat.getDateTimeInstance().format(new Date()));
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("TestJobBean 结束:::" + Thread.currentThread().getName() + ":::" + SimpleDateFormat.getDateTimeInstance().format(new Date()));
}
}
运行项目,log如下
我们只需看quartzScheduler_Worker-2这个任务的开始和结束之间,quartzScheduler_Worker-3和quartzScheduler_Worker-4这两个任务也同时在执行,并未等quartzScheduler_Worker-2任务结束后才执行,说明该定时任务是并发的
TestJobBean 开始:::quartzScheduler_Worker-2:::Aug 5, 2020 3:15:42 PM // quartzScheduler_Worker-2任务开始
TestJobBean 开始:::quartzScheduler_Worker-3:::Aug 5, 2020 3:15:43 PM
TestJobBean 开始:::quartzScheduler_Worker-4:::Aug 5, 2020 3:15:46 PM
TestJobBean 结束:::quartzScheduler_Worker-2:::Aug 5, 2020 3:15:48 PM // quartzScheduler_Worker-2任务结束
TestJobBean 开始:::quartzScheduler_Worker-5:::Aug 5, 2020 3:15:49 PM
TestJobBean 结束:::quartzScheduler_Worker-3:::Aug 5, 2020 3:15:49 PM
TestJobBean 开始:::quartzScheduler_Worker-6:::Aug 5, 2020 3:15:52 PM
TestJobBean 结束:::quartzScheduler_Worker-4:::Aug 5, 2020 3:15:52 PM
TestJobBean 结束:::quartzScheduler_Worker-5:::Aug 5, 2020 3:15:55 PM
TestJobBean 开始:::quartzScheduler_Worker-7:::Aug 5, 2020 3:15:55 PM
TestJobBean 开始:::quartzScheduler_Worker-8:::Aug 5, 2020 3:15:58 PM
TestJobBean 结束:::quartzScheduler_Worker-6:::Aug 5, 2020 3:15:58 PM
TestJobBean 开始:::quartzScheduler_Worker-10:::Aug 5, 2020 3:16:01 PM
TestJobBean 结束:::quartzScheduler_Worker-7:::Aug 5, 2020 3:16:01 PM
TestJobBean 开始:::quartzScheduler_Worker-1:::Aug 5, 2020 3:16:04 PM
串行(非并发)
在原来的定时任务上添加@DisallowConcurrentExecution注解就可以禁止并发
@DisallowConcurrentExecution // 禁止并发执行
@Service
public class TestJobBean extends QuartzJobBean {
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext) {
System.out.println("TestJobBean 开始:::" + Thread.currentThread().getName() + ":::" + SimpleDateFormat.getDateTimeInstance().format(new Date()));
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("TestJobBean 结束:::" + Thread.currentThread().getName() + ":::" + SimpleDateFormat.getDateTimeInstance().format(new Date()));
}
}
运行项目,打印log如下
可以看到log非常工整,都是一个任务结束后才开始下一个任务,说明该定时任务是串行的
TestJobBean 开始:::quartzScheduler_Worker-2:::Aug 5, 2020 3:12:14 PM
TestJobBean 结束:::quartzScheduler_Worker-2:::Aug 5, 2020 3:12:20 PM
TestJobBean 开始:::quartzScheduler_Worker-3:::Aug 5, 2020 3:12:20 PM
TestJobBean 结束:::quartzScheduler_Worker-3:::Aug 5, 2020 3:12:26 PM
TestJobBean 开始:::quartzScheduler_Worker-4:::Aug 5, 2020 3:12:27 PM
TestJobBean 结束:::quartzScheduler_Worker-4:::Aug 5, 2020 3:12:33 PM
TestJobBean 开始:::quartzScheduler_Worker-6:::Aug 5, 2020 3:12:33 PM
TestJobBean 结束:::quartzScheduler_Worker-6:::Aug 5, 2020 3:12:39 PM
TestJobBean 开始:::quartzScheduler_Worker-7:::Aug 5, 2020 3:12:42 PM
TestJobBean 结束:::quartzScheduler_Worker-7:::Aug 5, 2020 3:12:48 PM
TestJobBean 开始:::quartzScheduler_Worker-8:::Aug 5, 2020 3:12:48 PM
TestJobBean 结束:::quartzScheduler_Worker-8:::Aug 5, 2020 3:12:54 PM
TestJobBean 开始:::quartzScheduler_Worker-10:::Aug 5, 2020 3:12:57 PM
TestJobBean 结束:::quartzScheduler_Worker-10:::Aug 5, 2020 3:13:03 PM
TestJobBean 开始:::quartzScheduler_Worker-1:::Aug 5, 2020 3:13:03 PM
TestJobBean 结束:::quartzScheduler_Worker-1:::Aug 5, 2020 3:13:09 PM
TestJobBean 开始:::quartzScheduler_Worker-3:::Aug 5, 2020 3:13:12 PM
TestJobBean 结束:::quartzScheduler_Worker-3:::Aug 5, 2020 3:13:18 PM
TestJobBean 开始:::quartzScheduler_Worker-4:::Aug 5, 2020 3:13:18 PM
TestJobBean 结束:::quartzScheduler_Worker-4:::Aug 5, 2020 3:13:24 PM