SpringBoot-并发执行定时任务配置

普通定时任务的编写

开启定时任务支持

@SpringBootApplication
//配置类注解@EnableScheduling来开启对计划任务的支持
@EnableScheduling  
public class Application {
	
	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}
}

编写定时任务执行内容
编写一个用于执行定时任务的类,类上需要添加2个注解@Component
@EnableScheduling,编写执行方法一个方法就是一个定时任务,使用@Scheduled指定定时任务的执行时间

@Component
@EnableScheduling
public class MyTask {
	//每隔1000毫秒执行一次
    @Scheduled(fixedRate = 1000)
    private void Tasks1() {
        logger.warn("触发定时任务,当前执行线程池:{} 时间:{}",Thread.currentThread().getName(), DateUtils.getDateTime());
        logger.warn("定时任务结束{}",DateUtils.getDateTime());
    }
}

以上就是一个简单的定时任务了,但是其中存在一个问题就是springboot的定时任务默认是单线程的,那意味着如果我的系统处于高并发访问的情况下这个定时任务就会被一直推迟执行,如现在有一个定时任务需要在中午执行,但是由于中午网站并发大,主线程没有空导致定时任务一直被推迟到晚上,这不是我们想要的结果,我们可以通过多线程的方式,来解决这个问题

并发执行定时任务

解决办法也很简单创建一个类加上@Configuration注解,实现SchedulingConfigurer接口重写configureTasks方法在set定时任务的时候我们为他创建一个线程池,至于为什么要用ScheduledThreadPool线程池下面有解释

@Configuration
public class ScheduleConfig implements SchedulingConfigurer {
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setScheduler(Executors.newScheduledThreadPool(2));
    }
}

最终我们可以从日志中看到,我们的定时任务可以进行并发执行了,再也不用担心因为主线程没空而导致我们的定时任务推出甚至无法执行

springboot mysql datasource 并发数_spring boot

ScheduledThreadPool

为什么使用ScheduledThreadPool线程池来执行我们定时任务,首先我们从ScheduledThreadPoolExecutor方法中可以看到线程池初始化的时候传入的参数最主要的一个参数 DelayedWorkQueue() 队列下面有该队列的解释

springboot mysql datasource 并发数_spring boot_02


DelayedWorkQueue队列是什么

DelayedWorkQueue的工作就是按照执行时间的升序来排列,执行时间距离当前时间越近的任务在队列的前面,因为队列的先后顺序都是按照任务执行时间出/入栈的,所该队列很适合执行定时任务