浅谈Spring定时任务
三种定时任务基于原理
多定时任务并发配置
动态定时任务
定时任务Demo
三种定时任务基于原理
SpringBoot配置定时任务主要有Spring Schedule、JDK自带的TimeTask以及第三方的quartz框架
- SpringBoot开启一个定时任务,主要分为以下两步:
- 需要执行定时任务方法上加@Scheduled注解
- 配置@EnableScheduling开启定时任务。其中@Scheduled注解可以配置fixedRate固定频率执行(若超时,则在当前方法执行完成后立即执行)、fixedDelay固定间隔执行(从上次任务结束时间算)以及自定义cron表达式。
Spring Schedule默认会创建一个单线程池执行定时任务(Spring会搜索相关的线程池定义,要么在上下文中搜索唯一的TaskExecutor bean,要么搜索名为“taskExecutor”的Executor bean,如果两者都无法解析,则将使用SimpleAsyncTaskExecutor来处理异步方法调用)当需要多个任务并发(或需要在同一时间)执行,任务调度器就会出现时间漂移,因此通常需要给定时任务自定义配置一个线程池ThreadPoolTaskScheduler
- TimeTask是按照任务下个执行时间进行堆排序,每次取堆中的最小时间和当前系统时间进行比较,若当前时间大于下个任务执行时间则执行,将任务从最小堆中移除因此Timer定时任务是单线程+堆排序+轮询,并不适合多任务的管理
- quartz可以通过cron表达式精确到特定时间执行,每次执行任务都会创建一个新的任务类对象而且抛出异常不会影响下次任务执行,但Timer抛出异常整个定时器生命周期就会结束,quartz支持持久化、事务管理以及集群模式对多定时任务调度管理具有一定优势
多定时任务并发配置
Spring Schedule配置多定时任务并发,一般需要自定义配置线程池,主要有两种方式
- 第一种方式,使用时需要@Async(“指定线程池”)
@Configuration
@EnableAsync
public class ThreadPoolTaskConfig {
private static final int corePoolSize = 10; // 核心线程数(默认线程数)
private static final int maxPoolSize = 100; // 最大线程数
private static final int keepAliveTime = 10; // 允许线程空闲时间(单位:默认为秒)
private static final int queueCapacity = 200; // 缓冲队列数
private static final String threadNamePrefix = "Async-Service-"; // 线程池名前缀
@Bean("taskExecutor") // bean的名称,默认为首字母小写的方法名
public ThreadPoolTaskExecutor getAsyncExecutor(){
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setKeepAliveSeconds(keepAliveTime);
executor.setThreadNamePrefix(threadNamePrefix);
// 线程池对拒绝任务的处理策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 初始化
executor.initialize();
return executor;
}
}
- 第二种方式,直接实现AsyncConfigurer接口,重写getAsyncExecutor方法即可
@Configuration
@EnableAsync
public class AppConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(7);
executor.setMaxPoolSize(42);
executor.setQueueCapacity(11);
executor.setThreadNamePrefix("MyExecutor-");
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new MyAsyncUncaughtExceptionHandler();
}
}
动态定时任务
- 动态定时任务
定时任务Demo
- 定时任务Demo