时间轮算法HashedWheelTimer
文章目錄
- 一.HashedWheelTimer是什么?
- 二.能干什么?為什么需要這個東西?
- 優點
- 適用場景
- 三.怎么用?使用步驟
- 1.引入pom
- 2.使用舉例
- 四.時間輪原理
- 五.使用注意點
- 1.一個HashedWheelTimer對象只有一個worker線程
- 2.每次添加的任務只會執行一次
- 3.時間輪的參數非常重要
- 4.所有的任務都是順序串行執行的
一.HashedWheelTimer是什么?
???時間輪是一種非常驚艷的數據結構。其在Linux內核中使用廣泛,是Linux內核定時器的實現方法和基礎之一。
???換句話說時間輪是一種高效來利用線程資源來進行批量化調度的一種調度模型。把大批量的調度任務全部都綁定到同一個的調度器上面,使用這一個調度器來進行所有任務的管理(manager),觸發(trigger)以及運行(runnable)。能夠高效的管理各種延時任務,周期任務,通知任務等等
???而HashedWheelTimer則是使用了時間輪這種數據結構,它是Netty內部的一個工具類,最開始主要用來優化I/O超時的檢測,本文將詳細分析HashedWheelTimer的使用及原理。
二.能干什么?為什么需要這個東西?
優點
??????其實筆者認為其最大的優點就是可以在一個線程中動態的添加定時(延時)任務
像我們經常使用Timer,ScheduledExecutorService,Spring的Scheduled這些都是無法做到這一點的,一旦某個線程開始執行某個定時任務,都是無法再去動態添加的
??????那某些場景,比如說有很多小的定時任務,難道每一個都去起一個線程處理嗎?那數量多的話對程序勢必影響很大,浪費資源,這個時候就可以考慮HashedWheelTimer了.
??????而在netty中,因為其可能管理上百萬的連接,每一個連接都會有很多超時任務。比如發送超時、心跳檢測間隔等,如果每一個定時任務都啟動一個Timer,不僅低效,而且會消耗大量的資源。所以創造了這個工具類.
適用場景
三.怎么用?使用步驟
1.引入pom
<dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.45.Final</version> </dependency>2.使用舉例
1.構建對象,添加定時任務
//在一個格子里面的并不會區分的很細,而會依次順序執行,所以適用于對時間精度要求不高的任務//構建時間輪對象HashedWheelTimer timer = new HashedWheelTimer(5, TimeUnit.SECONDS, 10);//添加定時任務1,延遲2s執行timer.newTimeout((TimerTask) timeout -> {System.out.println("任務1執行");System.out.println("線程名稱:"+Thread.currentThread().getName());},2,TimeUnit.SECONDS);//添加定時任務2,延遲2s執行timer.newTimeout((TimerTask) timeout -> {System.out.println("任務2執行");System.out.println("線程名稱:"+Thread.currentThread().getName());},5,TimeUnit.SECONDS);//等待定時任務執行完畢后,將時間輪內部工作線程停止,這里只是粗略的等待,也可以使用CountDownLatchThread.sleep(10000);timer.stop();2.取消某個定時任務
//構建時間輪對象HashedWheelTimer timer = new HashedWheelTimer(1, TimeUnit.SECONDS, 10);//添加定時任務1Timeout newTimeout = timer.newTimeout((TimerTask) timeout -> {System.out.println("任務1執行");System.out.println("線程名稱:" + Thread.currentThread().getName());}, 5, TimeUnit.SECONDS);//現在又想取消掉這個任務if(!newTimeout.isExpired()){newTimeout.cancel();}四.時間輪原理
???時間輪其實就是一種環形的數據結構,可以想象成時鐘,分成很多格子,一個格子代碼一段時間(這個時間越短,Timer的精度越高)。并用一個鏈表表示在該格子上的到期任務,同時一個指針隨著時間一格一格轉動,并執行相應格子中的到期任務。任務通過取摸決定放入那個格子。如下圖所示:
???假設一個格子是1秒,則整個wheel能表示的時間段為8s,假如當前指針指向2,此時需要調度一個3s后執行的任務,顯然應該加入到(2+3=5)的方格中,指針再走3次就可以執行了;如果任務要在10s后執行,應該等指針走完一個round零2格再執行,因此應放入4,同時將round(1)保存到任務中。檢查到期任務時應當只執行round為0的,格子上其他任務的round應減1。
再回頭看看構造方法的三個參數分別代表
- tickDuration
每一tick的時間 - timeUnit
tickDuration的時間單位 - ticksPerWheel
就是輪子一共有多個格子,即要多少個tick才能走完這個wheel一圈。
五.使用注意點
1.一個HashedWheelTimer對象只有一個worker線程
2.每次添加的任務只會執行一次
3.時間輪的參數非常重要
???比如我這里設置每個格子的時間為6s,添加了兩個定時任務,一個延時2s執行,一個延時5s執行,但是最終執行結果是同時執行,因為這兩個任務都被分配到第一個格子中,按順序執行.
???所以時間輪的參數要根據時間情況具體設定
4.所有的任務都是順序串行執行的
也就是說上一個任務的異常延時會影響到下一個任務.
比如我這里添加了兩個定時任務,第一個延時2s,第二個延時5s,但是因為第一個任務的延時,導致第二個延時了10s才執行.
所以這里要求時間輪執行的任務都是比較快的, 或者這里可以使用異步任務去處理.
今天的分享就到這里了,有問題可以在評論區留言,均會及時回復呀.
我是bling,未來不會太差,只要我們不要太懶就行, 咱們下期見.
總結
以上是生活随笔為你收集整理的时间轮算法HashedWheelTimer的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 新办的卡为什么显示无服务器,为什么插入卡
- 下一篇: 计划扑克(Planning Poker)