spring boot定时任务原理 (springboot配置定时任务)

概述

SpringBoot定时任务常用方案:Schedule、Quartz。Schedule属于spring框架内置的功能,所属资源包spring-context-support;开发简单、执行效率高,多任务场景需要结合线程池(线程池大小需要谨慎设置)共同使用,以避免出现阻塞、崩溃、延迟启动等现象。Quartz纯Java开源调度框架,集群模式通过故障转移和负载平衡功能提供高可用性和可扩展性。本文主要探究Schedule,暂不考虑Quartz。Schedule以表达式加载方式维度可以分为:静态表达式、动态表达式,以执行模式维度可以分为:单线程、多线程。

springboot编写定时任务,springboot获取所有定时任务

静态表达式单线程

设置两个定时任务,通过sleep模拟task1耗时10s

//不受上次执行时间点影响,每隔5秒再执行。
@Scheduled(cron = "0/5 * * * * *")
    private void cronTask1() {
logger.info("task1"+Thread.currentThread().getName()+""+newDate().toString());
        //模拟定时任务卡死
        try {
            Thread.sleep(10000);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

@Scheduled(cron="0/5*****")
privatevoidcronTask2(){
logger.info("task2"+Thread.currentThread().getName()+""+newDate().toString());
}

springboot编写定时任务,springboot获取所有定时任务

如上图所示,本来预期效果是要两个定时任务都是每5s执行,实际效果是都是15s(10s的耗时)。默认情况下,Schedule调度任务使用单一线程串行执行。如果只有一个任务,这样做没问题。如果多个任务,一旦有任务耗时较长或者卡死,会直接导致其他任务延迟或者卡死。这种情况,就需要启用多线程。

静态表达式多线程

定义线程池

@Configuration
@EnableAsync   //开启线程池
public class AsyncConfigurer2 implements AsyncConfigurer {
    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(100);
        executor.setQueueCapacity(10);
        executor.setThreadNamePrefix("AsyncConfigurer2-");
        executor.initialize();
        return executor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new SimpleAsyncUncaughtExceptionHandler();
    }
}

定时任务启用线程池

    @Async   //使用线程池
    @Scheduled(cron = "* * * * * *")
    public void task() {
        logger.info(Thread.currentThread().getName() + " " + new Date().toString());
        //模拟定时任务卡死
        try {
            Thread.sleep(5000);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

如果还是使用单线程,本来定时每秒调度间隔,由于模拟任务卡死耗时5秒,调度间隔会成为6秒。启用多线程,会达到预期的调度间隔每秒的效果,如下图:

springboot编写定时任务,springboot获取所有定时任务

完整代码​:https://github.com/felixzh2020/felixzh-learning-springboot​