这两天发现生产上某些定时任务没有正常执行,查了下发现 Spring Boot 使用 @Scheduled 执行定时任务是在单线程中,由于数据量增长过大,导致定时任务执行时间过长,导致其他后续任务阻塞、卡死,导致其它任务没有执行。
单线程
可以看到,默认的线程池大小为1,所以定时任务是单线程执行的。
- org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration
- org.springframework.boot.autoconfigure.task.TaskSchedulingProperties
1 2 3 4 5 6 7 8 9 10 11 12
| @ConfigurationProperties("spring.task.scheduling") public class TaskSchedulingProperties { ... public static class Pool {
private int size = 1; } ... }
|
优化方案
1. 调整线程池大小
多线程执行,两个不同任务无需互相等待,但是同一个任务仍然需要等待。
1 2 3 4 5 6 7
| spring: task: scheduling: pool: size: 10 thread-name-prefix: mall-scheduling-
|
2. 指定线程池,异步执行
多线程执行,同一个任务也无需等待。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| @Configuration public class ThreadPoolConfig { @Bean("mallTaskExecutor") public Executor asyncServiceExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(5); executor.setMaxPoolSize(15); executor.setQueueCapacity(200); executor.setThreadNamePrefix("mall-async-executor-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); executor.initialize(); return executor; } }
@Async("mallTaskExecutor") @Scheduled(cron = "30 0 0 * * ? ") @SchedulerLock(name = "dayStats", lockAtMostFor = "86400000", lockAtLeastFor = "82800000") public void dayStats() { log.info("开始执行日统计任务"); ... }
|