一個專案中一般都少不了定時任務,主要用來處理一些特殊的任務,有的是隻執行一次的
定時任務,有的是週期迴圈執行的定時任務。可根據專案需要來選擇定時任務型別。自己參與
開發的一個專案中,因為很多定時任務都是需要週期執行的,因此選用按週期迴圈執行的方式。
比如幾分鐘過載一次主表資料,過載資料字典表資料,定時更新主表資料狀態,定時更新快取
資料到資料庫中的定時任務等等。因此在專案最開始設計的時候,架構人員就考慮使用使用
週期性定時任務來處理各種任務。
整體的大致思路是在專案啟動的時候,立馬啟動固定的執行緒數,比如18個執行緒,然後讓
這些執行緒去輪流執行定時任務,建立方式為Executors.newFixedThreadPool(20)。這種方式是
阿里巴巴的《Java開發手冊》中推薦的建立執行緒的一種方式。建立完執行緒池後,下一步就是
使用執行緒物件去定時執行任務,可以傳入一些引數,比如延遲啟動時間,執行間隔時間,需要
執行的任務物件等等。最後一步最重要的,就是寫定時任務處理類,定時任務類需要實現Runnable
介面,然後重寫run方法,接下來主要的定時任務邏輯都寫在run方法中。
定時任務類中可能會查詢資料庫資料,或者是參照其他的service服務類來處理業務邏輯,這時
需要新增一個@Component註解即可將這個類交給Spring統一處理,也能自動注入需要使用的其他類。
自己最近寫的一個定時任務也是同樣的處理方式。資料的處理流程為,使用定時任務1將符合條件的
表A中的資料定時新增到記憶體中;使用定時任務2將符合要求的表A的資料,按照一定的規則新增到
表B中,並且將表B返回的ID新增到redis佇列中;使用定時任務3從redis佇列中獲取資料,如果佇列
中有資料,則進行後續處理,將表B中的資料按照一定的規則新增到表C。這樣整個業務流程都串起來,
使用者登入系統後直接查詢表C的資料即可。
自己寫好功能後,反反覆覆地進行測試,發現一些問題,比如定時任務在一個週期內只想時間過長,
還未執行完成,下一次的執行任務又開始執行。這顯然是不符合要求的,那怎麼解決呢?看過同事以前
寫的程式碼,解決辦法為新增分散式鎖。自己立馬去修復這個問題,對於需要新增分散式鎖的兩個定時任務
立馬新增分散式鎖,執行之前先獲取鎖,如果獲取到鎖則執行定時任務,沒有獲取到鎖這不執行任務。
經過測試問題解決。第二個問題是,執行時間間隔的問題,本地開發環境只有單個伺服器在執行,測試
環境中也只有一臺伺服器執行,都沒問題,可是生產環境上有多臺伺服器在執行,定時任務的執行時間
就需要從新分配。比如某個定時任務計劃是10s執行一次,生產環境有5臺,就需要將間隔時間設定
為50s執行一次,不然可能出現的問題就是執行頻率遠遠大於10s。因為是多臺伺服器在同時執行定時
任務,而且開始執行的時間還不一致,所及執行時間間隔需要慎重計算。
曾經參與開發過的專案中,有的會有一個單獨的定時任務專案,用來執行各種可設定的定時任務,
當然這些都是根據具體專案來選用和開發的。以上就是關於定時任務執行的整個設計思路,有其他
更好建議的小夥伴,歡迎留言討論。