周期性定時任務
周期性定時任務
一、業務場景
Web項目開發中少不了需要使用定時任務來處理一些工作,比如定時更改某些數據的狀態,定時進行統計操作等等。
自己以前參與開發過的一些系統中還有一些專門的定時任務處理子系統,用來根據具體的業務需要實現一些非常複雜的
定時任務處理操作。有的定時任務只需要執行一次,比如手機上設置的某一天某人結婚的定時鬧鐘提醒;有的任務需要
重複的執行,比如上班日早上起床時的鬧鐘。今天要分享的定時任務處理操作只針對特定場景,就是周期性循環執行的
任務。
二、實現方案
看過阿里巴巴開源的Java開發手冊的同學都知道,裡面關於多執行緒的章節,寫了這麼一條,
【強制】多執行緒並行處理定時任務時,Timer 運行多個 TimeTask 時,只要其中之一沒有捕獲
拋出的異常,其它任務便會自動終止運行,使用 ScheduledExecutorService 則沒有這個問題。
今天要講的內容就也是採用這種方式來實現的,使用ScheduledExecutorService這個類。首先創建一個單獨的服務service類,
類似於Service的實現類比如ServiceOneImpl,在這個類中寫一個具體的方法,方法裡面就是需要執行的具體任務的程式碼。真實
的開發中可以直接使用Service介面調用即可,示例程式碼如下:
@Slf4j
@Service
public class ServiceOneImpl {
public void doTaskOne() {
log.info(“執行任務一“);
}
}
然後寫一個任務類,比如TaskOne這個類,讓其實現Runnable介面,然後重寫run方法。並且在這個類中,注入 ServiceOneImpl這個類,
然後在run方法中調用需要執行的doTaskOne()方法,示例程式碼如下:
@Component
public class TaskOne implements Runnable{
@Resource
private ServiceOneImpl serviceOneImpl;
@Override
public void run() {
this.serviceOneImpl.doTaskOne();
}
}
最後一步是寫一個具體的定時任務執行類,用來統一管理所有需要執行的定時任務操作,並且需要注入ScheduledExecutorService來
創建多個執行緒,使用不同的執行緒去執行不同的任務。示例程式碼如下:
@Slf4j
@Component
public class TimingTaskScheduler {
@Resource
private TaskOne taskOne;
// 創建20個執行緒
ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(20);
@PostConstruct
public void initialize() {
// 參數一為需要執行的任務類 參數二為延遲時間 參數三為執行周期 參數四為時間單位
executorService.scheduleWithFixedDelay(taskOne, 1000L, 1000L, TimeUnit.MILLISECONDS);
}
}
到此這個定時任務的程式碼就完成了。這裡面使用到了一個註解@PostConstruct,被這個註解標識的方法在伺服器載入Servlet的
時候運行,並且只會被伺服器調用一次。可以參考博文 //www.cnblogs.com/YuyuanNo1/p/8184003.html 。當伺服器啟動
的時候,就會觸發 initialize() 這個方法執行一次,然後就會觸發ScheduledExecutorService 一直不斷地去執行裡面的定時任務。
scheduleWithFixedDelay方法需要四個參數,第一個參數是需要執行的定時任務類,第二個參數是項目啟動後的延遲執行時間,
第三個參數是執行的間隔周期,第四個參數是時間單位。真實項目中後面的兩個參數都可以統一的寫在一個配置文件當中,
然後使用配置文件來統一的進行設置延遲執行時間,執行周期,或者是是否執行的開關等等。
執行效果如下:
執行的執行緒也是不一樣的,符合實際的預期,利用多執行緒來進行執行。目前已經使用這種方式來處理的一些定時任務有:
.a.定時更新字典錶快取數據的任務;
.b.定時更新某張重要的錶快取數據的任務;
.c.定時更新某個介面查詢快取數據的任務;
.d.定時處理某統計操作的任務;
.e.定時處理其他複雜計算的任務;
有需要的小夥伴可以考慮使用這種方式來進行處理,阿里巴巴都推薦這麼使用。有其他更好建議的小夥伴歡迎留言談論。