文章字数:675,阅读全文大约需要2分钟
通过类上设置注解
@EnableScheduling
可以开启spring自带的定时任务,@Scheduled
设置定时时间。还可以通过ThreadPoolTaskScheduler
的schedule(Runable,cron)
动态添加
使用
1 |
|
固定时间匹配规则
字段 | 允许值 | 允许的特殊字符 |
---|---|---|
秒 | 0-59 | , - * / |
分 | 0-59 | , - * / |
小时 | 0-23 | , - * / |
日期 | 1-31 | , - * ? / L W C |
月份 | 1-12 或者 JAN-DEC | , - * / |
星期 | 1-7 或者 SUN-SAT | , - * ? / L C # |
年 | 空, 1970-2099 | , - * / |
- 每个元素都可以是一个值如
6
,一个区间9-12
一个间隔时间8-18/4
/4
代表间隔四个小时,一个列表1,3,5
- 日期和星期互斥,即两个元素重合,必须其中一个设置
?
忽略 *
代表所有可能的值/
指定数值的增量,如0/10
(分钟单位中)代表0分钟开始,10分钟执行一次?
仅在日期和星期中,代表不指定值L
用于日期和星期中,代表倒数第几个W
仅在日其中,代表平日(工作日)。15W
代表离15号最近的一个工作日。C
日期,5C
五个单位后的第一天#
每个月第几个星期几,例如在4#2
表示某月的第二个星期三。
转换异步线程
单线程执行时间超过定时间隔可能会出现任务丢失的情况,可以使用异步线程避免这个问题。
- 配置
Spring
的@EnableAsync
- 执行方法上配置任务线程池
@Async
1
2
3
4
5
6//每30秒执行一次
"taskExecutor") (
1000 * 3) (fixedRate =
public void xxx(){
//...
}
分布式情况下避免重复执行
lock = redisTemplate.opsForValue().setIfAbsent(KEY, LOCK);
采用Redis
判断是否存在key
,不存在则设置key
,执行完成删除key
的方式加锁(跨时区部署还是会重复执行)shedlock
加锁配置(jdbc),还有redis,mongo,zookeeper等锁的实现1
2
3
4
5
6
7
8
9
10
11<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-spring</artifactId>
<version>0.16.1</version>
</dependency>
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-jdbc-template</artifactId>
<version>0.16.1</version>
</dependency>shedlock表1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class ShedlockConfig {
public LockProvider lockProvider(DataSource dataSource) {
return new JdbcTemplateLockProvider(dataSource);
}
public ScheduledLockConfiguration scheduledLockConfiguration(LockProvider lockProvider) {
return ScheduledLockConfigurationBuilder
.withLockProvider(lockProvider)
.withPoolSize(10)
.withDefaultLockAtMostFor(Duration.ofMinutes(10))//lock expire最大时间10分钟
.build();
}
}加锁1
2
3
4
5
6
7CREATE TABLE shedlock(
name VARCHAR(64),
lock_until TIMESTAMP(3) NULL,
locked_at TIMESTAMP(3) NULL,
locked_by VARCHAR(255),
PRIMARY KEY (name)
)1
2
3
4
510*1000 /**ms**/,initialDelay = 10*1000) (fixedDelay =
"demoLockTask", lockAtMostFor = 5*1000) (name =
public void checkTask(){
LOGGER.error("checkTask executed");
}
动态添加关闭定时任务
1 | // 引入定时调度线程池 |