SpringBoot 定时任务
基于注解,静态执行周期
Spring Task 是 Spring 提供的轻量级定时任务工具,相比于其他第三方类库更加方便易用。
新建配置类,添加
@EnableScheduling
注解开启SpringTask。
@Configuration
@EnableScheduling
public class SpringTaskConfiguration {
}
创建定时任务类,使用
@Scheduled
注解注册Cron
表达式执行定时任务。
@Slf4j
@Component
public class CronTask {
@Scheduled(cron = "0/1 * * ? * ?")
public void cron() {
log.info("cron:{}", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
}
}

默认情况下,@Scheduled
创建的线程池大小为1,如果想增加线程池大小的话,可以让SpringTaskConfiguration
类实现SchedulingConfigurer
接口,通过setPoolSize
增加线程池大小。
@Configuration
@EnableScheduling
public class SpringTaskConfiguration implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
var threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setPoolSize(10); // 设置线程池线程数量
threadPoolTaskScheduler.setThreadNamePrefix("task-"); // 设置线程名称前缀
threadPoolTaskScheduler.initialize(); // 初始化线程池
taskRegistrar.setScheduler(threadPoolTaskScheduler);
}
}

Spring Task 除了支持Cron表达式,还有fixedRate(固定速率执行)、fixedDelay(固定延迟执行)、initialDelay(初始延迟)三种用法。
// 固定速率执行。每5秒执行一次。
@Scheduled(fixedRate = 5000)
public void reportCurrentTimeWithFixedRate() {
log.info("Current Thread : {}", Thread.currentThread().getName());
log.info("Fixed Rate Task : The time is now {}", DateUtil.now());
}
动态设置执行周期(基于接口)
使用@Scheduled
注解很方便,但缺点是当调整了执行周期后,需要重新打包部署才能生效,为了省去这一步,我们可以将执行周期存在数据库或者相关的配置文件中,服务可以从数据库或者配置中读取。
@Configuration
@EnableScheduling
public class SpringTaskConfiguration implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.addTriggerTask(() -> {
// 任务逻辑
System.out.println("执行定时任务");
}, triggerContext -> {
// 此处的cron表达式可以从数据库或配置文件中读取,方便实现定时任务的动态配置
String cron = "0/5 * * * * ?";
CronTrigger cronTrigger = new CronTrigger(cron);
return cronTrigger.nextExecution(triggerContext);
});
}
}
多线程定时任务
@Component
@EnableAsync
public class CornTask {
@Async
@Scheduled(fixedDelay = 1000) //间隔1秒
public void first() throws InterruptedException {
System.out.println("第一个定时任务开始 : " + LocalDateTime.now().toLocalTime() + "\r\n线程 : " + Thread.currentThread().getName());
System.out.println();
Thread.sleep(1000 * 10);
}
@Async
@Scheduled(fixedDelay = 2000)
public void second() {
System.out.println("第二个定时任务开始 : " + LocalDateTime.now().toLocalTime() + "\r\n线程 : " + Thread.currentThread().getName());
System.out.println();
}
}
Corn 表达式
Cron表达式是一个含有时间意义的字符串,以5个空格隔开,分成6个时间元素。例如:
0 15 10 ? * *
每天上午10:15执行任务
0 0 10,14,16 * * ?
每天10 点、14 点、16 点执行任务
0 0 12 ? * 3
每个星期三中午 12 点执行任务
0 15 10 15 * ?
每月 15 日上午 10 点 15 执行任务
每个时间元素的取值范围,以及可出现的特殊字符如下所示。
秒
[0,59]
*,-/
分钟
[0,59]
*,-/
小时
[0,59]
*,-/
日期
[0,31]
*,-/?LW
月份
[1,12]
*,-/
星期
[1,7]
*,-/?L#
特殊字符的含义和示例如下所示。
*
所有可能的值
很好理解,月域中为每个月,星期域中每个星期几
,
枚举的值
很好理解,小时域中 10,14,16
,就表示这几个小时可选
-
范围
很好理解,分钟域中 10-19
,就表示 10-19 分钟每隔一分钟执行一次
/
指定数值的增量
很好理解,分钟域中 0/15
,就表示每隔 15 分钟执行一次
?
不指定值
很好理解,日期域指定了星期域就不能指定值,反之亦然,因为日期域和星期域属于冲突关系
L
单词 Last 的首字母
很好理解,日期域和星期域支持,表示月的最后一天或者星期的最后一天
W
除周末以外的工作日
很好理解,仅日期域支持
#
每个月的第几个星期几
很好理解,仅星期域支持,4#2
表示某月的第二个星期四
最后更新于
这有帮助吗?