不少小夥伴在實際開發中,必定碰到過須要定時去執行某些業務邏輯的時候,解決方案有不少,好比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
OK,咱們再看看控制檯打印的是什麼?執行動態定時任務: 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
複製代碼
看,因爲開啓了多線程,第一個任務的執行時間也不受其自己執行時間的限制。兩個任務也互不影響。