一、時間輪演算法簡介
為了大家能夠理解下文中的代碼,我們先來簡單了解一下netty時間輪演算法的核心原理

時間輪演算法名副其實,時間輪就是一個環形的資料結構,類似于表盤,將時間輪分成多個bucket(比如:0-8),假設每個時間輪輪片的分隔時間段tickDuration=1s(即:指標經過每個格子花費時間是 1 s),當前的時間bucket=3,那么在18秒后需要被執行的任務需要落到((3+18)%8=5取余運算)的5號bucket上,假如有多個需要在該時間段內執行的任務,就會組成一個雙向鏈表,
另外針對時間輪我們要有下面的幾個認知:
- 時間輪指標是一個Worker執行緒,在時間輪整點的時候執行雙向鏈表中的任務,
- 時間輪演算法的并不是精準的延時,它的執行精度取決于每個時間輪輪片的分隔時間段tickDuration
- Worker執行緒是單執行緒,一個bucket、一個bucket的順序處理任務,所以我們的延時任務一定要做成異步任務,否則會影響時間輪后續任務的執行時間,
二、時間輪hello-world
實作一個延時任務的例子,需求仍然十分的簡單:你買了一張火車票,必須在30分鐘之內付款,否則該訂單被自動取消,訂單30分鐘不付款自動取消,這個任務就是一個延時任務, 我們的火車票訂單取消任務,從需求上看并不需要非常精準的延時,所以是可以使用時間輪演算法來完成這個任務的,
首先通過maven坐標引入netty
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.45.Final</version>
</dependency>
然后我們創建一個時間輪,如果是Spring的開發環境,我們可以這么做,下文中我們new了一個包含512個bucket的時間輪,每個時間輪的輪片時間間隔是100毫秒,
@Bean("hashedWheelTimer")
public HashedWheelTimer hashedWheelTimer(){
return new HashedWheelTimer(100, TimeUnit.MILLISECONDS, 512);
}
舉例:當用戶買火車票下單的時候,向時間輪中添加一個30分鐘的延時任務,延時任務將在30分鐘之后被執行,下文的lambda運算式部分實作了一個TimerTask(task)延時任務,這個延時任務的函式體內,請一定使用異步任務,即:單獨起一個執行緒或者使用SpringBoot異步任務執行緒池,因為Worker執行緒是單執行緒的,你的任務處理時間長于tickDuration會妨礙后續時間輪輪片上的任務的執行,
//訂單下單操作
void order(String orderInfo) {
//下單的時候,向時間輪中添加一個30分鐘的延時任務
hashedWheelTimer.newTimeout(task -> {
//注意這里使用異步任務執行緒池或者開啟執行緒進行訂單取消任務的處理
cancelOrder(orderInfo);
}, 30, TimeUnit.MINUTES);
}
三、異步任務執行緒池
我們在上文中已經多次強調,時間輪的任務TimerTask的執行內容要做成異步的,最簡單的做法就是接到一個任務之后啟動一個執行緒處理該任務,在Spring環境下其實我們有更好的選擇,就是使用Spring的執行緒池,這個執行緒池是可以自定義的,比如:下文中的用法是我事先定義了一個名字為test的執行緒池,然后通過@Async使用即可,
@Async("test")
public void cancelOrder(String orderInfo){
//查詢訂單支付資訊,如果用戶未支付,關閉訂單
}
可能有的朋友,還不知道該如何自定義一個Spring執行緒池,可以參考:我之前寫過一個SpringBoot的可觀測、易配置的執行緒池開源專案,源代碼地址:https://gitee.com/hanxt/zimug-monitor-threadpool ,我的這個zimug-monitor-threadpool開源專案,可以做到對執行緒池使用情況的監控,我自己平時用的效果還不錯,向大家推薦一下!
四、時間輪優缺點
時間輪演算法實作延時任務的優點就是,相對于使用JDK的DelayQueue,其演算法上具有優勢,執行性能相對好一些,
其缺點就是所有的延時任務以及延時觸發的管理,都是在單個應用服務的記憶體中進行的,一旦該應用服務發生故障重啟服務,時間輪任務資料將全部丟失,這一缺點和DelayQueue是一樣的,為了解決這個問題,我們可以使用redis、RocketMQ等分布式中間件來管理延時任務訊息的方式來實作延時任務,這個我會在后續的文章中為大家介紹,
歡迎關注我的公告號:字母哥雜談,回復003贈送作者專欄《docker修煉之道》的PDF版本,30余篇精品docker文章,字母哥博客:zimug.com
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/502282.html
標籤:Java
