基于SpringBoot项目创建定时任务

40 阅读2分钟

什么是Cron表达式

cron表达式是由7个子表达式组成的字符串,每个子表达式代表一个时间域(秒、分钟、小时、日、月、周、年),用空格分隔。每个时间域都可以指定一个或多个值,范围或通配符,用于精确地定义任务的执行时刻。
例如,一个常见的cron表达式 "0 0 12 * * ?" 表示每天12点整执行任务。
以下是cron表达式各部分的详细说明:

  • 秒(0-59)
  • 分钟(0-59)
  • 小时(0-23)
  • 日(1-31)
  • 月(1-12)
  • 周(1-7,其中1和7代表周日)
  • 年(1970-2199,可选)

cron表达式还支持特殊字符,如星号(*)代表任意值,逗号(,)用于列举多个值,连字符(-)用于指定范围,斜线(/)用于指定步长等。

Cron表达式在线生成工具

基本使用

启动类添加@EnableScheduling注解

@SpringBootApplication
@EnableScheduling
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}

业务类定时任务添加@Scheduled注解

@Component
public class MyScheduleTask {

    // 每3秒执行一次
    @Scheduled(cron = "*/3 * * * * ?")
    public void repeatPrintTime(){
        System.out.printf("task1 %s %s%n", Thread.currentThread().getName(), LocalTime.now().toString());
    }
}

思考

启动多个定时任务时,定时任务之间会互相影响吗?

定时任务默认是单线程的,当task1未执行完成时,task2会阻塞

解决:实现SchedulingConfigurer接口,并重写configureTasks方法

import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;

import java.util.concurrent.Executors;


@Configuration
public class ScheduleConfig implements SchedulingConfigurer {
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        // 结合实际情况配置
        int corePoolSize = taskRegistrar.getScheduledTasks().size()
                + taskRegistrar.getCronTaskList().size()
                + taskRegistrar.getFixedDelayTaskList().size()
                + taskRegistrar.getFixedRateTaskList().size()
                + 3
                ;

        taskRegistrar.setScheduler(Executors.newScheduledThreadPool(corePoolSize));
        System.out.printf("ScheduleConfig corePoolSize: %d %n", corePoolSize);
    }
}

同一个定时任务,上一个定时任务执行未结束,下一个定时任务是否会执行?

上一个定时任务未执行完成时,下一个定时任务会阻塞; 但是定时任务的启动时间一直符合@Scheduled设置规则

解决:业务逻辑使用线程池去执行,定时任务只起到调用的作用

@Component
@EnableAsync
public class MyScheduleTask {

    // 每3秒执行一次
    @Scheduled(cron = "*/3 * * * * ?")
    public void repeatPrintTime() throws InterruptedException {
        System.out.printf("task1 start %s %s%n", Thread.currentThread().getName(), LocalTime.now().toString());
        asyncPrintTime();
        System.out.printf("task1 end   %s %s%n", Thread.currentThread().getName(), LocalTime.now().toString());
    }

    // 注意自定义线程池配置
    @Async
    public void asyncPrintTime() throws InterruptedException {
        Thread.sleep(10*1000);
    }
}

定时任务增加分布式锁

待补充~~~

定时任务原理

待补充~~~