從Dubbo的線程池拒絕策略到線程泄露分析

       開篇講一下,爲什麼要寫線程池飽和後的拒絕策略。早在上個月,就要說寫一篇除 java.util.concurrent包之外的四種線程池拒絕策略,開源框架如:ActiveMQ,Dubbo,PinPoint,Netty也都實現了符合自己業務的拒絕策略。

然而一直沒有動手,直到今天手殘的點開一篇博客如下:

本打算快速瀏覽一遍,竟然看到不敢相信的幾行代碼,代碼如下:

       首先,這是業務操作是:在執行了自定義的拒絕策略後,調用方法dumpJStack() 用輸出流的方式輸出線程信息到某個路徑的文件。那麼問題來了,這種在方法內部創建的線程池會不會有線程泄露的風險?這種行編碼方式也決定了接下來的代碼不可能有shutdown()這樣的操作。

-------------------------------------------- 格嘰格嘰格嘰格嘰格嘰格嘰 一休哥來啦----------------------------------------------

那我們自己來實驗一下到底有沒有問題吧!

       可以確定的是局部創建的線程池是不會在方法執行完畢後回收,具體爲什麼局部線程池沒有被回收,不在本文討論的重點,請自行百度一下。這裏只用簡單的代碼測試一下這個結論。


測試代碼如下:

先來看反例代碼及線程監控:

執行一次後的線程視圖和dump下的信息:

       經過分析上圖,發現局部線程池在線程任務執行完畢後線程沒有被回收,而是wating的狀態駐留,從而導致線程泄露(因爲不可能再使用到這個線程池)。

反例分析過後,修改下測試代碼,再次對比,如何回收局部線程池

正例代碼測試:

修改的代碼中打開了shutdown的註釋。

觀察幾張圖,可以確定的是線程被回收了,從而避免了線程泄露。

       現在可以真正的確定如果沒有手動調用shutdown,局部的線程池創建會存在線程泄露的風險,那麼Duboo中是否真的像開篇的文章一樣,沒有回收線程呢?

       本着對阿里的敬意,從最大的同性交友網站GitHub上down下源碼,下面是貼源碼時間。

首先找到了線程池相關的類

Dubbo中實現了自己的線程池,但本質上還是ThreadPoolExecutor。

經查看幾種線程池的飽和策略都是一個叫作

AbortPolicyWithReport的策略類。

找到了正主,發現是繼承了併發包下的一個直接拋異常的拒絕策略

重寫了rejectedExecution方法

但是發現和本文開始的代碼貼圖不太一樣。對,就是你想的那樣,這裏的局部線程池被回收了,腳趾頭想一下也不相信會有這麼低級的錯誤,而且註釋很有意思。

那麼爲什麼開篇文章的貼圖中會沒有回收的代碼,本着開源精神,查看一下git log,果然如此。

在19年1月份已經被修復了。

下面我們再來看一下,Dubbo的拒絕策略到底做了什麼。

首先輸出warn級別的線程池信息日誌,打印的日誌真是標準的典範。

然後dump下線程相關信息,就是這樣。

Dubbo的線程池拒絕策略就是上述內容,沒有什麼難度,但是很標準的記錄了飽和當時的線程信息,方便排查。

接下來會分享其他開源框架中關於線程池拒絕策略的分析,感謝呦

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章