Spring Boot四种类型的任务调度以及自定义任务调用的线程池
本文主要围绕以下两方面内容介绍Spring Boot 集成任务调用:
- 基于@Scheduled注解定义任务调度的用法
- 自定义任务调度的线程池
Spring Boot开启任务调度
Spring Boot 开启任务调度很简单,只需要在启动的Application类,或者配置类上添加注解@EnableScheduling即可。
如以下示例:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
四种类型的任务调度
Spring定义任务调度也很简单,只需要在类的方法上添加注解@Scheduled。根据任务的类型设置相应的参数,可以分为以下四种类型设置任务调用:
- 固定速率的任务调度
- 固定延迟的任务调用
- 固定速率和初始延迟任务调度
- 使用cron表达式设置任务
定义任务调度的方法需要满足以下条件:
- 方法返回值需要是void
- 方法不接受任何参数
固定速率的任务调度
可以通过使用 @Scheduled 注释中的 fixedRate 参数来设置方法以固定的时间间隔执行。
下面示例表示方法将每 2 秒执行一次:
@Scheduled(fixedRate = 2000)
public void scheduleTaskWithFixedRate() {
logger.info("Fixed Rate Task :: Execution Time - {}", dateTimeFormatter.format(LocalDateTime.now()) );
}
输出如下:
Fixed Rate Task :: Execution Time - 22:26:58
Fixed Rate Task :: Execution Time - 22:27:00
Fixed Rate Task :: Execution Time - 22:27:02
从输出结果看出,参数fixedRate设置的任务,会以固定的时间间隔执行。即使之前的任务调用没有完成,也会以指定的时间间隔调用任务。
固定延迟的任务调用
可以使用fixedDelay参数在上次调用完成和下一次调用开始之间以固定延迟执行任务。
示例:
@Scheduled(fixedDelay = 2000)
public void scheduleTaskWithFixedDelay() {
logger.info("Fixed Delay Task :: Execution Time - {}", dateTimeFormatter.format(LocalDateTime.now()));
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException ex) {
throw new IllegalStateException(ex);
}
logger.info("Fixed Delay Task :: Finished Time - {}", dateTimeFormatter.format(LocalDateTime.now()));
}
输出如下:
Fixed Delay Task :: Execution Time - 22:30:01
Fixed Delay Task :: Finished Time - 22:30:06
Fixed Delay Task :: Execution Time - 10:30:08
Fixed Delay Task :: Finished Time - 22:30:13
Fixed Delay Task :: Execution Time - 10:30:15
Fixed Delay Task :: Finished Time - 22:30:20
可以见到:下一个任务是在上一个任务结束后2秒开始执行。
固定速率和初始延迟任务调度
可以使用参数initialDelay来设置第一个任务的延迟时间。
示例:
@Scheduled(fixedRate = 2000, initialDelay = 5000)
public void scheduleTaskWithInitialDelay() {
logger.info("Fixed Rate Task with Initial Delay :: Execution Time - {}", dateTimeFormatter.format(LocalDateTime.now()));
}
此示例中:任务第一次执行会延迟5秒,然后以2秒的固定间隔正常执行
使用cron表达式设置任务
如果任务的执行时间比较复杂,如每天某时某刻执行任务,那么以上的参数就不足以表达。Spring的Schedule提供了cron参数,我们可以通过cron参数来设置任务。
示例如下:
@Scheduled(cron = "0 * * * * ?")
public void scheduleTaskWithCronExpression() {
logger.info("Cron Task :: Execution Time - {}", dateTimeFormatter.format(LocalDateTime.now()));
}
此cron表达式表示每分钟执行一次任务。
自定义任务调用的线程池
默认情况下,所有@Scheduled 任务都在 Spring 创建的大小为 1 的默认线程池中执行。如果想知道任务在哪个线程执行,可以按以下的方式输出日志:
LOGGER.info("Current Thread : {}", Thread.currentThread().getName());
除了使用Spring提供的默认线程池,Spring也允许我们自定义任务执行的线程池。
示例:
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
@Configuration
public class SchedulerConfig implements SchedulingConfigurer {
private final static int POOL_SIZE = 10;
@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setPoolSize(POOL_SIZE);
threadPoolTaskScheduler.setThreadNamePrefix("scheduled-task-pool-");
threadPoolTaskScheduler.initialize();
scheduledTaskRegistrar.setTaskScheduler(threadPoolTaskScheduler);
}
}
示例中定义了大小为10的线程池。并且设置了线程的前缀为"scheduled-task-pool-"
在输出的日志中就可以看到:
Current Thread : scheduled-task-pool-1
Current Thread : scheduled-task-pool-2