@Scheduled默认单线程
在 Spring 框架中,@Scheduled
注解默认使用单线程的任务调度器(TaskScheduler
),这会导致多个定时任务只能串行执行,一个任务阻塞会影响其他所有任务。
核心思路是自定义一个多线程的TaskScheduler
或ScheduledExecutorService
,替代 Spring 默认的单线程调度器。
解决方案:配置多线程任务调度器
方案 1:直接配置 ThreadPoolTaskScheduler(推荐)
通过创建ThreadPoolTaskScheduler
类型的 Bean,指定线程池参数,Spring 会自动使用该调度器执行所有@Scheduled
任务。
java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
@Configuration
@EnableScheduling // 启用定时任务
public class ScheduledConfig {
@Bean
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
// 设置核心线程数(根据任务数量调整,一般5-10即可)
scheduler.setPoolSize(5);
// 设置线程名称前缀(方便日志排查)
scheduler.setThreadNamePrefix("scheduled-task-");
// 任务执行完后是否关闭线程池
scheduler.setWaitForTasksToCompleteOnShutdown(true);
// 等待任务完成的超时时间(秒)
scheduler.setAwaitTerminationSeconds(60);
scheduler.initialize();
return scheduler;
}
}
方案 2:实现 SchedulingConfigurer 接口(更灵活)
通过实现SchedulingConfigurer
接口,自定义任务注册器的线程池,适合需要更细粒度配置的场景。
java
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import java.util.concurrent.Executors;
@Configuration
@EnableScheduling
public class ScheduledConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
// 创建一个固定大小的线程池(5个线程)
taskRegistrar.setScheduler(Executors.newScheduledThreadPool(5,
r -> {
Thread thread = new Thread(r);
thread.setName("scheduled-task-"); // 线程名称前缀
thread.setDaemon(false); // 非守护线程(避免主线程退出后被强制终止)
return thread;
}));
}
}
关键配置说明
- 线程池大小(PoolSize) :
根据定时任务的数量和执行频率调整,避免线程过多导致资源浪费,或线程过少仍存在排队问题(建议 5-20,视业务复杂度而定)。 - 线程名称前缀 :
方便在日志中区分不同任务的线程,便于问题排查。 - 任务关闭策略 :
setWaitForTasksToCompleteOnShutdown(true)
:应用关闭时,等待所有任务执行完成再关闭线程池。setAwaitTerminationSeconds(60)
:设置等待超时时间,防止任务无限阻塞。
注意事项
- 配置后,所有
@Scheduled
任务会并行执行(受限于线程池大小),需确保任务本身是线程安全的(避免共享资源竞争)。 - 若部分任务需要单独的线程池(如高优先级任务),可通过
@Async
结合自定义线程池实现更灵活的调度。
通过以上配置,即可解决@Scheduled
默认单线程的问题,让定时任务能够并行高效执行。