Field Name Mandatory Allowed Values Allowed Special Characters
Seconds YES 0-59 , - * /
Minutes YES 0-59 , - * /
Hours YES 0-23 , - * /
Day of month YES 1-31 , - * ? / L W
Month YES 1-12 or JAN-DEC , - * /
Day of week YES 1-7 or SUN-SAT , - * ? / L #
Year NO empty, 1970-2099 , - * /

特殊字符:

(cron="7,9,23 * * * * ?") 表示任意时刻的 7、9、23秒启动这个任务。

(cron="7-20 * * * * ?") 表示7到20秒之间,每秒启动一次该任务。

(cron="7/5 * * * * ?") 表示第7秒启动,每5秒一次

(cron="*/5 * * * * ?") 表示任意秒启动,每5秒一次

? 出现在日和周的位置

为了防止日和周冲突,在周和日上如果要写通配符使用 ?

(cron="* * * 1 * ?") 每月的1号启动这个任务

L 出现在日和周的位置 last:最后一个

(cron="* * * ? * 3L") 每月的最后一个周二

W Work Day 工作日:

(cron="* * * W * ?") 每个月的工作日触发

(cron="* * * LW * ?") 每个月的最后一个工作日触发

# 第几个

(cron="* * * ? * 5#2") 每个月的第二个周四

SpringBoot 整合定时任务

由于 SpringBoot 原生就支持定时任务,所以我们只需要使用 EnableScheduling 注解开启即可,当然还需要将他加入到容器中。

@Component
@EnableScheduling
public class HelloSchedule { ... }

使用 @Scheduled 注解创建一个定时任务,指定每分钟的第10秒启动,每5秒执行一次

@Slf4j
@Component
@EnableScheduling
public class HelloSchedule {
  @Scheduled(cron = "10/5 * * * * ?")
  private void hello() {
    log.info("每分钟的第10秒启动,每5秒执行一次,当前是第 {} 秒", new Date().getSeconds());
每分钟的第10秒启动,每5秒执行一次,当前是第 10 秒
每分钟的第10秒启动,每5秒执行一次,当前是第 15 秒
每分钟的第10秒启动,每5秒执行一次,当前是第 20 秒
每分钟的第10秒启动,每5秒执行一次,当前是第 25 秒
每分钟的第10秒启动,每5秒执行一次,当前是第 30 秒
每分钟的第10秒启动,每5秒执行一次,当前是第 35 秒
每分钟的第10秒启动,每5秒执行一次,当前是第 40 秒
每分钟的第10秒启动,每5秒执行一次,当前是第 45 秒
每分钟的第10秒启动,每5秒执行一次,当前是第 50 秒
每分钟的第10秒启动,每5秒执行一次,当前是第 55 秒
每分钟的第10秒启动,每5秒执行一次,当前是第 10 秒
每分钟的第10秒启动,每5秒执行一次,当前是第 15 秒
每分钟的第10秒启动,每5秒执行一次,当前是第 20 秒
每分钟的第10秒启动,每5秒执行一次,当前是第 25 秒
每分钟的第10秒启动,每5秒执行一次,当前是第 30 秒
每分钟的第10秒启动,每5秒执行一次,当前是第 35 秒
每分钟的第10秒启动,每5秒执行一次,当前是第 40 秒
每分钟的第10秒启动,每5秒执行一次,当前是第 45 秒
每分钟的第10秒启动,每5秒执行一次,当前是第 50 秒
每分钟的第10秒启动,每5秒执行一次,当前是第 55 秒
每分钟的第10秒启动,每5秒执行一次,当前是第 10 秒
每分钟的第10秒启动,每5秒执行一次,当前是第 15 秒
每分钟的第10秒启动,每5秒执行一次,当前是第 20 秒

在 SpringBoot 中,周使用1-7分别表示周一到周日,个别定时任务每周的第一天是从周日开始。

在 SpringBoot 中,定时任务是阻塞的,也就是需要等待上一次的定时任务完成后才能再继续执行定时任务。这是因为在 SpringBoot 中支持使用定时任务线程池,而这个线程池默认大小为 1 导致的任务阻塞,这一般在业务中是不被允许的。

org.springframework.boot.autoconfigure.task.TaskSchedulingProperties

在配置文件中修改线程池为合适的大小

spring.task.scheduling.pool.size=12

在某些版本可能不起作用...

如果修改 scheduling 的线程池大小无效,那么还可以使用异步任务,这不仅仅可以用在定时任务上。

只需要使用 @EnableAsync 注解开启异步任务

@Slf4j
@Component
@EnableAsync
@EnableScheduling
public class HelloSchedule {}

并且在你需要异步执行的方法上再标注一个 @Async 注解即可

@Async
@Scheduled(cron = "10/5 * * * * ?")
public void hello() {
  log.info("每分钟的第10秒启动,每5秒执行一次,当前是第 {} 秒", new Date().getSeconds());