1.在啓動類上添加註解@EnableScheduling,如下圖所示:
2.創建配置類,添加註解@Scheduled
2.1 其中Schedule 三種任務調度器有:
2.1.1.fixedRate
固定頻率任務:
該屬性的含義是上一個調用開始後再次調用的延時(不用等待上一次調用完成),這樣就可能會存在任務重複執行的問題,所以不是建議使用,但數據量如果不大時在配置的間隔時間內可以執行完也是可以使用的。
注意:當方法的執行時間超過任務調度頻率時,調度器會在當前方法執行完成後立即執行下次任務。
示例代碼:
@Scheduled(fixedRate = 1000 * 10)
public void work() {
// do your work here
}
fixedRate 的單位是毫秒,上例中 fixedRate = 1000 * 10 表示每 10 秒執行一次。
設第一次執行開始時時間爲 0,正常情況下第二次執行開始時間是第 10 秒,第三次是第 20 秒……以此類推。
但假如任務在 10 秒內沒有完成,比如第一次花了 15秒完成任務,那第二次執行時間也是 第15 秒,會馬上執行。
2.1.2 fixedDelay
固定間隔任務:
下一次的任務執行時間,是從方法最後一次任務執行結束時間開始計算。並以此規則開始週期性的執行任務。
示例代碼:
@Scheduled(fixedDelay = 1000 * 10)
public void work() {
// do your work here
}
上例每隔10秒執行一次,設第一次執行開始時時間爲 0,如果任務的執行時間是 5 秒,那下次任務的開始時間是 5 + 10 = 15 即第 15 秒。再下一次任務開始執行時間是 15 + 5 + 10 = 30 即第 30 秒,以此類推
2.1.3 Cron表達式
Cron表達式由6或7個空格分隔的時間字段組成,如下圖:
- 第一位,表示秒,取值 0-59
- 第二位,表示分,取值 0-59
- 第三位,表示小時,取值 0-23
- 第四位,日期,取值 1-31
- 第五位,月份,取值 1-12
- 第六位,星期幾,取值 1-7
- 第七位,年份,可以留空,取值 1970-2099
(*) 星號:可以理解爲“每”的意思,每秒、沒分
(?) 問號:只能出現在日期和星期這兩個位置,表示這個位置的值不確定
(-) 表達一個範圍,如在小時字段中使用 10-12 ,表示從10點到12點
(,) 逗號,表達一個列表值,如在星期字段中使用 1,2,4 ,則表示星期一、星期二、星期四
(/) 斜槓,如 x/y ,x是開始值,y是步長,如在第一位(秒)使用 0/15,表示從0秒開始,每15秒
官方解釋:
0 0 3 * * ? 每天 3 點執行
0 5 3 * * ? 每天 3 點 5 分執行
0 5 3 ? * * 每天 3 點 5 分執行
0 5/10 3 * * ? 每天 3 點 5 分,15 分,25 分,35 分,45 分,55 分這幾個點執行
0 10 3 ? * 1 每週星期天的 3 點10 分執行,注:1 表示星期天
0 10 3 ? * 1 #3 每個月的第三個星期的星期天 執行,#號只能出現在星期的位置
注:第六位(星期幾)中的數字可能表達不太正確,可以使用英文縮寫來表示,如:Sun
注意,當方法的執行時間超過任務調度頻率時,調度器會在下個週期執行。
下面的例子,每 10 秒執行一次,但任務執行時間是 12 秒。
設第一次執行任務開始時間是 0,那第一次任務執行完應該是第 12 秒。第二次任務本應在第 10 秒開始執行,但由於第 10 秒時第一次任務還沒執行完,所以第二次任務會把第 10 秒這個節點跳過,等到第 20 秒再執行第二次任務。
@Scheduled(cron = "0/10 * * * * *")
public void test() throws InterruptedException {
log.info(Thread.currentThread().getName()+"---test");
TimeUnit.SECONDS.sleep(12);
}
3.配置 TaskScheduler 線程池
Spring 會默認創建一個單線程池,如果系統中有多個定時任務要執行,任務調度器就會出現時間漂移,任務執行時間將不確定。
所以我們自定義一個 TaskScheduler 線程池。
@Configuration
public class InitBeanConfig {
/**
* 配置 Schedule 的線程池.
*/
@Bean
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(10);
taskScheduler.setThreadNamePrefix("springboot-task");
return taskScheduler;
}
}
這樣當需要同時執行多個任務,就會最多開啓 10 個線程來處理。
本文參考掘金文章,不作商用,只爲分享,原文點擊此處