不少小伙伴在实际开发中,必定碰到过须要定时去执行某些业务逻辑的时候,解决方案有不少,好比MQ。不过在这里博主介绍的是springboot提供的比较好用的定时任务组件Schedule。java
你们都知道spring建立定时任务so esay,下面有三种方式:spring
基于注解 (@Scheduled)
基于接口 (SchedulingConfigurer)
基于注解设定多线程定时任务
须要注意的是@Scheduled默认是串行的,单线程,当开启多个任务时,任务的执行时机会受上一个任务执行时间的影响。数据库
@Configuration
@EnableScheduling //开启定时任务
public class ScheduleTask {
//每10秒执行一次
@Scheduled(cron = "0/10 * * * * ?")
private void configureTasks() {
System.out.println("我是一个定时任务");
}
}
复制代码
@Scheduled 除了cron还提供另外三种种方式: fixedRate,fixedDelay,initialDelay
一、cron表达式能够定制化执行任务,可是执行的方式是与fixedDelay相近的,也是会按照上一次方法结束时间开始算起。 二、fixedDelay控制方法执行的间隔时间,是以上一次方法执行完开始算起,如上一次方法执行阻塞住了,那么直到上一次执行完,并间隔给定的时间后,执行下一次。springboot
@Configuration
@EnableScheduling //开启定时任务
public class ScheduleTask {
//每10秒执行一次
@Scheduled(fixedDelay = 10000)
private void configureTasks() {
System.out.println("我是一个定时任务");
}
}
复制代码
三、fixedRate是按照必定的速率执行,是从上一次方法执行开始的时间算起,若是上一次方法阻塞住了,下一次也是不会执行,可是在阻塞这段时间内累计应该执行的次数,当再也不阻塞时,一会儿把这些所有执行掉,然后再按照固定速率继续执行。bash
@Configuration
@EnableScheduling //开启定时任务
public class ScheduleTask {
//每10秒执行一次
@Scheduled(fixedRate = 10000)
private void configureTasks() {
System.out.println("我是一个定时任务");
}
}
复制代码
四、initialDelay = 10000 表示在容器启动后,延迟10秒后再执行一次定时器。多线程
@Configuration
@EnableScheduling //开启定时任务
public class ScheduleTask {
//容器启动后,延迟10秒后再执行一次定时器,之后每10秒再执行一次该定时器。
@Scheduled(initialDelay = 10000, fixedRate = 10000)
private void configureTasks() {
System.out.println("我是一个定时任务");
}
}
复制代码
有些小猿可能发现,使用@Scheduled 注解很方便,但缺点是当咱们调整了执行周期的时候,须要重启应用才能生效,这多少有些不方便。为了达到实时生效的效果,那么可使用接口来完成定时任务。app
@Configuration
@EnableScheduling //开启定时任务
public class DynamicScheduleTask implements SchedulingConfigurer {
//从数据获取任务执行周期
@Autowired
private MyBatisMapper myBatisMapper;
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.addTriggerTask(
//1.添加任务内容(Runnable)
() -> System.out.println("执行动态定时任务: " + LocalDateTime.now().toLocalTime()),
//2.设置执行周期(Trigger)
triggerContext -> {
//2.1从数据库获取执行周期
String cron = myBatisMapper.getCron();
//2.2 返回执行周期(Date)
return new CronTrigger(cron).nextExecutionTime(triggerContext);
}
);
}
}
复制代码
数据库表数据以下:ide
好,咱们启动测试看看测试
执行动态定时任务: 17:17:00.008999
执行动态定时任务: 17:17:20.002501
执行动态定时任务: 17:17:30.001786
执行动态定时任务: 17:17:40.005512
执行动态定时任务: 17:17:50.005870
执行动态定时任务: 17:18:00.002189
执行动态定时任务: 17:18:10.001910
复制代码
咱们能够看到每10秒执行一次任务。那么如今要求每5秒执行一次,该怎么作呢?这个时候咱们只须要修改下数据库数据便可,无需重启。 spa
执行动态定时任务: 17:18:30.000902
执行动态定时任务: 17:18:40.001392
执行动态定时任务: 17:18:45.005027
执行动态定时任务: 17:18:50.001367
执行动态定时任务: 17:18:55.001356
执行动态定时任务: 17:19:00.001582
执行动态定时任务: 17:19:05.005676
执行动态定时任务: 17:19:10.001258
执行动态定时任务: 17:19:15.005272
复制代码
成功每5秒执行一次。是否是很嗨~
前面讲到了@Scheduled执行周期任务会受到上次一个任务的执行时间影响。那么能够开启多线程执行周期任务。
@EnableScheduling // 1.开启定时任务
@EnableAsync // 2.开启多线程
@Component
public class MultiThreadScheduleTask {
@Async
@Scheduled(fixedDelay = 1000) //间隔1秒
public void first() throws InterruptedException {
System.out.println("第一个定时任务开始 : " + LocalDateTime.now().toLocalTime() + "\r\n线程 : " + Thread.currentThread().getName());
Thread.sleep(1000 * 10);
}
@Async
@Scheduled(fixedDelay = 2000)
public void second() {
System.out.println("第二个定时任务开始 : " + LocalDateTime.now().toLocalTime() + "\r\n线程 : " + Thread.currentThread().getName());
}
}
复制代码
咱们重启下项目看看控制台输出什么:
第二个定时任务开始 : 17:27:01.024288
线程 : task-4
第一个定时任务开始 : 17:27:01.024393
线程 : task-7
第一个定时任务开始 : 17:27:02.027932
线程 : task-4
第二个定时任务开始 : 17:27:05.021294
线程 : task-1
第一个定时任务开始 : 17:27:05.021533
线程 : task-1
第一个定时任务开始 : 17:27:06.014213
复制代码
看,因为开启了多线程,第一个任务的执行时间也不受其自己执行时间的限制。两个任务也互不影响。