定时任务
cron 表达式
cron表达式语法:秒 分 时 日 月 周 年(spring暂不支持年)
| 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")每月的最后一个周二 -
WWork 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());
}