Spring的@Scheduled的默认线程池数量为1,也就是说定时任务是单线程执行的。这意味着最多同时只有一个任务在执行。当一个任务还在执行时,其他任务会等待其完成,然后按照其预定的执行策略依次执行。
测试代码:
启动类上加注解@EnableScheduling开启任务调度功能,具体任务调度代码如下:
@Slf4j
@Component
public class Scheduler {
// 每两秒执行一次
@Scheduled(fixedRate = 2000)
public void mockMethod1() {
long threadId = Thread.currentThread().getId();
String threadName = Thread.currentThread().getName();
log.info("mockMethod1 start with current thread id: {}, name: {}", threadId, threadName);
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("mockMethod1 end with current thread id: {}, name: {}", threadId, threadName);
}
@Scheduled(fixedRate = 2000)
public void mockMethod2() {
long threadId = Thread.currentThread().getId();
String threadName = Thread.currentThread().getName();
log.info("mockMethod2 start with current thread id: {}, name: {}", threadId, threadName);
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("mockMethod2 end with current thread id: {}, name: {}", threadId, threadName);
}
}
结果:可以看到mockMethod1执行完才会执行mockMethod2,而且是单线程执行
源码:
Spring的@Scheduled有个特点
就是,确保任务执行完毕后才会再次调度下一次执行
想要同时执行多个Scheduled,怎么办?
解决:
1.当如果有程序有多个任务的话需要修改配置,让其变为多线程执行,这种配置不会破坏Scheduled的特点
# 设置任务调度线程名称前缀
spring.task.scheduling.thread-name-prefix=task-schedule-
# 设置任务调度线程池大小
spring.task.scheduling.pool.size=10
# 设置任务调度线程池关闭时等待所有任务完成
spring.task.scheduling.shutdown.await-termination=true
结果:
2.使用@Async配置线程池,这种配置会破坏Scheduled的特点
启动类上加注解@EnableAsync开启异步功能,然后配置线程池
@Configuration
public class AppConfig {
@Bean("taskExecutor")
public ThreadPoolTaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(6); // 设置核心线程数
executor.setMaxPoolSize(9); // 设置最大线程数
executor.setQueueCapacity(25); // 设置任务队列容量
executor.setThreadNamePrefix("executor-");
return executor;
}
}
代码上加上异步
@Async("taskExecutor")
@Scheduled(fixedRate = 2000)
public void mockMethod1() {
long threadId = Thread.currentThread().getId();
String threadName = Thread.currentThread().getName();
log.info("mockMethod1 start with current thread id: {}, name: {}", threadId, threadName);
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("mockMethod1 end with current thread id: {}, name: {}", threadId, threadName);
}