Spring為任務調度和非同步方法執行提供註解支持。 1 啟用Scheduling註解 要啟用 @Scheduled 和 @Async ,在 @Configuration 類(或者在啟動類)添加 @EnableScheduling 和 @EnableAsync,如下: @Configuration @ ...
Spring為任務調度和非同步方法執行提供註解支持。
1 啟用Scheduling註解
要啟用 @Scheduled
和 @Async
,在 @Configuration
類(或者在啟動類)添加 @EnableScheduling
和 @EnableAsync
,如下:
@Configuration
@EnableAsync
@EnableScheduling
public class AppConfig {
}
@SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class,
})
@EnableScheduling
public class RoadSyncApplication {
public static void main(String[] args) {
SpringApplication.run(RoadSyncApplication.class, args);
}
}
你可以為你的應用程式選擇相關的註解。例如,如果你只需要支持 @Scheduled
,可以省略 @EnableAsync
。對於更細粒度的控制,你還可以分別實現 SchedulingConfigurer
介面和 AsyncConfigurer
介面。有關完整詳細信息,請參閱 SchedulingConfigurer
和 AsyncConfigurer
javadoc。
預設處理
@Async
註解的建議模式是proxy
,它僅允許通過代理攔截調用。使用這種方式無法攔截同一類中的本地調用。 對於更高級的攔截模式,請考慮切換到aspectj
模式與編譯時織入或載入時織入結合使用。
2 @Scheduled
註解
可將 @Scheduled
註解以及觸發元數據添加到方法中。
2.1 fixedDelay
如下方法每5000ms執行一次,採用固定延遲,即周期從每次先前調用的【完成時間】開始測量。
@Scheduled(fixedDelay = 5000)
public void doSomething() {
// 定期運行的內容
}
預設,固定延遲、固定速率和初始延遲的值將使用ms作時間單位。如想用不同時間單位,如s或min,可在 @Scheduled
配置 timeUnit
屬性:
@Scheduled(fixedDelay = 5, timeUnit = TimeUnit.SECONDS)
public void doSomething() {
}
2.2 fixedRate
如需固定速率執行,使用 fixedRate
屬性。下麵的方法每五秒(從每次【調用的開始時間】間隔測量)執行一次:
@Scheduled(fixedRate = 5, timeUnit = TimeUnit.SECONDS)
public void doSomething() {
}
固定延遲、固定速率的任務,可通過指示等待的時間量來指定初始延遲,然後再執行方法的第一次調用:
@Scheduled(initialDelay=1000, fixedRate=5000)
public void doSomething() {
// 定期運行的內容
}
2.3 一次性任務
可只指定通過指示等待執行方法的時間量的初始延遲:
@Scheduled(initialDelay=1000)
public void doSomething() {
// 只運行一次
}
若簡單的定期計劃不夠表達力,可用 cron 表達式:
@Scheduled(cron="*/5 * * * * MON-FRI")
public void doSomething() {
// 僅在工作日運行的內容
}
還可使用 zone
屬性指定解析 cron 表達式的時區。
要計劃的方法須有 void 返回值,且不接受任何參數。如果方法需要與應用程式上下文中的其他對象交互,那麼這些對象通常已經通過依賴註入。
@Scheduled
是可重覆註解。如在同一方法上找到幾個 scheduled 聲明,每個聲明都將獨立處理,為每個聲明觸發單獨的觸發器。因此,這樣的共定位計劃可並行重疊並立即連續執行多次。請確保你指定的 cron 表達式等不會意外重疊。
Spring Framework 4.3 開始,支持任何範圍的 bean 上的
@Scheduled
方法。確保在運行時不初始化同一@Scheduled
註解類的多個實例,除非你確實希望調度回調到每個這樣的實例。確保不要在使用
@Scheduled
註解並作為常規 Spring bean 註冊到容器中的 bean 類上使用@Configurable
。否則,你將獲得雙重初始化(一次通過容器,一次通過@Configurable
方面),其結果是每個@Scheduled
方法被調用兩次。
FAQ
問題
生產用@Scheduled註解寫定時任務,5min執行一次:
@Scheduled(cron = "0 0/5 * * * ?")
public void MyTimerJobSchedule() throws Exception {
//省略具體業務邏輯
System.out.println("五分鐘執行一次");
}
過幾天,領導通知說有問題,一查日誌,發現是定時任務問題。本來應該是5min跑一次,結果日誌發現,每天0點-3點正常,3-10點沒執行;一直到10-11點之間才繼續跑。
原因
發現可能是定時任務單線程模式導致任務阻塞。
繼續分析日誌,發現該定時任務的線程號是[Scheduling-1],除了執行自身的任務,還列印了其它定時任務的輸出語句。
每天3點前,[Scheduling-1]線程在執行本人寫的5min一次的定時任務,3點後,[Scheduling-1]線程會執行另一個比較耗時的定時任務,直到10點後,[Scheduling-1]線程才重新執行5min一次的定時任務。
看來,確實是由於@Scheduled定時任務預設使用單線程模式導致:一旦有一個定時任務比較耗時,就會影響到其它定時任務按時執行。
解決方法
在定時任務加@Async註解,併在啟動類增加@EnableAsync註解,使用多線程模式執行定時任務。
備註:
參考網址:https://blog.csdn.net/LYM0721/article/details/89499588
參考網址中有第二種解決方法,但是已說明不太好用,因此只用第一種解決方法就夠了。
本文由博客一文多發平臺 OpenWrite 發佈!