日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

时间轮算法解析(Netty HashedWheelTimer源码解读)

發(fā)布時(shí)間:2024/4/13 编程问答 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 时间轮算法解析(Netty HashedWheelTimer源码解读) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1、背景

時(shí)間輪算法可以用于高效的執(zhí)行大量的定時(shí)任務(wù)。

在Netty中的一個(gè)典型應(yīng)用場景是判斷某個(gè)連接是否idle,如果idle(如客戶端由于網(wǎng)絡(luò)原因?qū)е碌椒?wù)器的心跳無法送達(dá)),則服務(wù)器會(huì)主動(dòng)斷開連接,釋放資源。得益于Netty NIO的優(yōu)異性能,基于Netty開發(fā)的服務(wù)器可以維持大量的長連接,單臺(tái)8核16G的云主機(jī)可以同時(shí)維持幾十萬長連接,及時(shí)掐掉不活躍的連接就顯得尤其重要。

2、算法簡介

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

網(wǎng)上盜個(gè)圖,時(shí)間輪算法可以通過上圖來描述。假設(shè)時(shí)間輪大小為8,1s轉(zhuǎn)一格,每格指向一個(gè)鏈表,保存著待執(zhí)行的任務(wù)。

假設(shè),當(dāng)前位于2,現(xiàn)在要添加一個(gè)3s后指向的任務(wù),則2+3=5,在第5格的鏈表中添加一個(gè)節(jié)點(diǎn)指向任務(wù)即可,標(biāo)識(shí)round=0。

假設(shè),當(dāng)前位于2,現(xiàn)在要添加一個(gè)10s后指向的任務(wù),則(2+10)% 8 = 4,則在第4格添加一個(gè)節(jié)點(diǎn)指向任務(wù),并標(biāo)識(shí)round=1,則當(dāng)時(shí)間輪第二次經(jīng)過第4格時(shí),即會(huì)執(zhí)行任務(wù)。

時(shí)間輪只會(huì)執(zhí)行round=0的任務(wù),并會(huì)把該格子上的其他任務(wù)的round減1。

算法的原理非常淺顯易懂,但是閱讀源碼實(shí)現(xiàn)還是有益的。

3、源碼解析

1、構(gòu)造方法

參數(shù):

1)threadFactory

用于生成工作線程

2)tickDuration和unit

每格的時(shí)間間隔,默認(rèn)100ms

3)ticksPerWheel

一圈下來有幾格,默認(rèn)512,特別的,如果傳入的不是2的N次方,則會(huì)調(diào)整為大于等于該參數(shù)的第一個(gè)2的N次方,好處是可以優(yōu)化hash值的計(jì)算

4)leakDetection

如果false,那么只有工作線程不是后臺(tái)線程時(shí)才會(huì)追蹤資源泄露,這個(gè)參數(shù)可以忽略

5)maxPendingTimeouts

最大的pending數(shù)量,默認(rèn)-1,表示不限制

注:可以看到構(gòu)造方法執(zhí)行結(jié)束時(shí),工作線程并沒有啟動(dòng),那么應(yīng)該是在第一次添加任務(wù)的時(shí)候啟動(dòng)的,我們繼續(xù)看添加任務(wù)的newTimeout方法

2、newTimeout

首先,通過一個(gè)原子變量來計(jì)數(shù)當(dāng)前的任務(wù)數(shù),如果設(shè)置最大pending且超過了,則會(huì)直接throw Exception

其次,便是調(diào)用start方法來正式啟用worker線程,為了防止重復(fù)調(diào)用,使用了一個(gè)原子操作,并且調(diào)用完畢之后會(huì)CountDownLatch.await阻塞住,直到線程完全起來才返回

?

可以看到,方法是public的,也即用戶可以顯示的調(diào)用,而無需等待第一次添加任務(wù)時(shí)再啟動(dòng)

最后,便是包裝一個(gè)HashedWheelTimeout對(duì)象(計(jì)算出了deadline),丟給隊(duì)列,等待工作線程處理,那么接下來的重點(diǎn)就是看worker線程的實(shí)現(xiàn)了

?

3、Worker線程

工作線程啟動(dòng)的第一步是初始化startTime,并調(diào)用countDown來通知start方法,初始化結(jié)束了

其次便是一個(gè)循環(huán),循環(huán)內(nèi)的行為就是每隔一段跳一格的操作了,我們看具體的操作:

1)首先調(diào)用waitForNextTick()

?

首先計(jì)算一下當(dāng)前tick下的deadline,減去startTime,得到sleepTimeMs,隨后sleep一下。這里面有幾個(gè)小細(xì)節(jié):

計(jì)算sleepTimeMs先加999999,應(yīng)該是不足1ms的,補(bǔ)足1ms

因?yàn)槊看螆?zhí)行定時(shí)任務(wù)消耗的時(shí)候是不受控制的,因此算出來的sleepTimeMs可能為負(fù),這個(gè)時(shí)候就可以直接返回了執(zhí)行下一個(gè)格子里的任務(wù)了

如果currentTime==Long.MIN_VALUE,會(huì)直接返回一個(gè)負(fù)數(shù),這個(gè)應(yīng)該是為了處理時(shí)間輪執(zhí)行了很長時(shí)間導(dǎo)致的long值溢出,具體了解的可以評(píng)論里告訴,不勝感激

下面還有一個(gè),如果是windows平臺(tái),先除以10再乘以10,是因?yàn)閣indows平臺(tái)下最小調(diào)度單位是10ms,如果不處理成10ms的倍數(shù),可能導(dǎo)致sleep更不準(zhǔn)了

最后,如果線程被打斷了,并且是shutdown狀態(tài),會(huì)直接返回負(fù)數(shù),并在隨后的while判斷中挑出循環(huán)

2)隨后調(diào)用processCanceldTasks()

該方法是為了處理那些被取消的任務(wù),任務(wù)存放在一個(gè)queue中

?

3)transferTimeoutsToBuckets()

該方法是從timeouts(就是前面newTimeout是放進(jìn)去的那個(gè)queue)的queue中取出任務(wù),放到格子里(HashedWheelBucket是一個(gè)鏈表),為了防止這個(gè)操作銷毀太多時(shí)間,導(dǎo)致更多的任務(wù)時(shí)間不準(zhǔn),因此一次最多操作10w個(gè)。幾個(gè)注意點(diǎn):

計(jì)算stopIndes時(shí),含義是取模,因?yàn)閙ask是2的N次方減1,因此%和&可以等價(jià)操作,即x % (mask + 1) == x & mask,這個(gè)技巧在jdk的集合類中也被使用到

為了防止出現(xiàn)任務(wù)延遲太久,因此在計(jì)算模之前,還先取max in (calculated, tick),從而讓那些本應(yīng)該在 過去執(zhí)行的任務(wù),在這期先快速執(zhí)行掉

?

4)expireTimeouts(deadline)

這是HashedWheelBucket的一個(gè)方法,就是來執(zhí)行該格子里那些已經(jīng)過期的任務(wù)

這步的操作比較簡單,就是一次遍歷鏈表,如果remainingRounds(剩下的圈數(shù))小于等于0,那么就把他移除并執(zhí)行expire方法(即TimerTask的run方法);如果任務(wù)被取消了,則直接移除;否則remainingRounds減一,等待下一圈

?

5)如果中間時(shí)間輪的狀態(tài)不再是started,那么就會(huì)跳出循環(huán),并依次取出各個(gè)bucket上的未執(zhí)行且沒有被取消的任務(wù),stop方法會(huì)返回這個(gè)列表

4、總結(jié)

? 時(shí)間輪算法理解起來很簡單,實(shí)現(xiàn)也似乎不難,但是通過閱讀源碼,可以看到,其中還是有很多很多的小細(xì)節(jié)需要注意,這個(gè)就不容易了

? 而且通過閱讀源碼,可以看到,整個(gè)時(shí)間輪的調(diào)度都是在一個(gè)線程里完成的,因此對(duì)于那些耗時(shí)較大的定時(shí)任務(wù),如果直接扔進(jìn)去處理顯然會(huì)影響其他任務(wù)的正常執(zhí)行,例子如下:

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

?

?

轉(zhuǎn)載:https://sq.163yun.com/blog/article/177510753845874688

總結(jié)

以上是生活随笔為你收集整理的时间轮算法解析(Netty HashedWheelTimer源码解读)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。