Spring Boot四种类型的任务调度以及自定义任务调用的线程池

时间:2021-09-21 16:30:59

本文主要围绕以下两方面内容介绍Spring Boot 集成任务调用:

  1. 基于@Scheduled注解定义任务调度的用法
  2. 自定义任务调度的线程池

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。根据任务的类型设置相应的参数,可以分为以下四种类型设置任务调用:

  1. 固定速率的任务调度
  2. 固定延迟的任务调用
  3. 固定速率和初始延迟任务调度
  4. 使用cron表达式设置任务

定义任务调度的方法需要满足以下条件:

  1. 方法返回值需要是void
  2. 方法不接受任何参数

固定速率的任务调度

可以通过使用 @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