在現代應用開發中,定時任務是一個常見的需求。比如,我們可能需要定時清理過期數據、定時發送郵件通知等。
操作流程
開啟定時任務注解
在啟動類添加注解@EnableScheduling
設置時間(固定時間間隔)
使用?@Scheduled
?注解創建定時任務十分簡單,只需幾行代碼就能完成。@Scheduled
?除了支持靈活的?cron
?參數表達式,還支持簡單的延時操作,如?fixedDelay
(任務執行結束后延遲指定毫秒數再執行下一次)、fixedRate
(固定頻率,每隔指定毫秒數執行一次)。
@EnableScheduling
@SpringBootApplication
public class DingshiApplication {public static void main(String[] args) {SpringApplication.run(DingshiApplication.class, args);}//下面的兩個方法在第一次啟動項目的時候會執行一次// 半小時提醒一次@Scheduled(fixedRate = 30*60*1000)public void playSth1(){System.out.println("任務一"+ DateFormat.getDateInstance().format(new Date()));}// 四小時執行一次@Scheduled(fixedRate = 4*60*60*1000)public void playSth2(){System.out.println("任務二"+ DateFormat.getDateInstance().format(new Date()));}
}
cron表達式
Cron 表達式是一種用于指定定時任務執行時間的字符串表達式。它由 6 個字段組成,分別表示秒、分鐘、小時、天數、月份和星期幾。每個字段都可以使用特定的符號來指定時間范圍或間隔。
Cron - 在線Cron表達式生成器
- , :表示列出枚舉值。例如:在 分鐘 域使用5,20,表示在時間的分鐘數為5,20時觸發事件。
- - :表示范圍:例如在 分鐘 域使用5-20,表示在時間的分鐘數為5到20時每分鐘都觸發事件
- * :表示匹配該域的任意值。假如在 分鐘 域使用*,表示時間分鐘數不做限制,分分鐘都出發事件
- / :表示起始時間開始觸發,然后每個固定時間觸發一次。例如在 分鐘 域使用5/20,表示事件的分鐘數為5時觸發一次,后隔20分鐘即25,45再分別觸發一次。
spring中只可以使用6位。
0 0 2 1 * ?:每月一號凌晨兩點觸發。
0 10,44 14 ? 3 WED :3月的每個星期3下午兩點10分和44分時觸發
- ?:只能用在DayofMonth和DayofWeek兩個域,由于DayOfMonth和DayOfWeek互斥,需對其一進行設置。
- L:表示最后,只能出現在DayofWeek和DayofMonth域。如果在DayofWeek域使用5L,意味著在最后一個星期四觸發。
- W:表示有效工作日(周一到周五),只能出現在DayofMoneth域,系統將在離指定日期的最近的有效工作日觸發事件。
- #:用于確定每個月第幾個星期幾,只能出現在DayofWeek域。例如在4#2,表示某月的第二個星期三
- C:只能用在DayofMonth和DayofWeek兩個域,需要關聯日歷,如果沒關聯可以忽略
- 專有符號中除了?外,再Spring定時任務中都不支持。
spring異步多線程實現
@Async
?是 Spring 框架中的一個任務異步執行注解,在定時任務中主要有以下作用:
- 避免任務阻塞:Spring 中添加了?
@Scheduled
?注解的定時任務默認都在一個線程中執行,這意味著當某個定時任務執行時間較長時,其他定時任務會一直等待,出現排隊現象。而使用?@Async
?注解后,被注解的定時任務方法會使用新線程異步執行,避免了任務之間的相互阻塞。例如,有任務 A 需要長時間處理數據,任務 B 是定時發送簡單通知,如果沒有?@Async
,任務 B 需等任務 A 完成才能執行;添加?@Async
?后,任務 B 可在新線程中異步執行,不被任務 A 阻塞。 - 提高執行效率:在存在多個定時任務的場景下,通過?
@Async
?讓任務在不同線程中并行執行,充分利用多核 CPU 的性能,提高整體執行效率。比如,一個系統中有定時數據備份任務、定時日志清理任務和定時數據統計任務,使用?@Async
?可使這些任務同時進行,而不是依次排隊執行。 - 增強系統穩定性:當某個定時任務因異常掛死時,若沒有?
@Async
,會影響后續定時任務的執行;使用?@Async
?后,每個任務在獨立線程中運行,某個任務的異常不會導致其他任務無法執行,增強了系統的穩定性和健壯性。
不過需要注意,使用?@Async
?時,Spring Boot 默認執行器線程池大小為 100 ,開發者也可根據實際需求自定義線程池配置,以更好地管理異步任務的執行。
樣例展示
@EnableAsync
@EnableScheduling
@SpringBootApplication
public class DingshiApplication {public static void main(String[] args) {SpringApplication.run(DingshiApplication.class, args);}//下面的兩個方法在第一次啟動項目的時候會執行一次@Async@Scheduled(fixedRate = 5*1000)public void playSth1(){System.out.println("任務1線程:"+Thread.currentThread().getName());System.out.println("任務一"+ DateFormat.getDateInstance().format(new Date()));}@Async@Scheduled(cron = "0 0 2 1 * ? ")@Scheduled(fixedRate = 10*1000)public void playSth2(){System.out.println("任務2線程:"+Thread.currentThread().getName());System.out.println("任務二"+ DateFormat.getDateInstance().format(new Date()));}
}