日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當(dāng)前位置:首頁(yè) > 科技  > 軟件

不同業(yè)務(wù)使用同一個(gè)線程池發(fā)生死鎖

來源: 責(zé)編: 時(shí)間:2024-09-10 09:50:21 143觀看
導(dǎo)讀在我們進(jìn)行代碼開發(fā)時(shí),我也見過很多全局注冊(cè)一個(gè)自定義線程池(也有可能不是自定義的,直接使用更不推薦Executors 創(chuàng)建的線程池),也許是業(yè)務(wù)量不高、也許是其他原因,反正全局可這一個(gè)線程池使勁造。一、看個(gè)代碼業(yè)務(wù)邏輯代碼

在我們進(jìn)行代碼開發(fā)時(shí),我也見過很多全局注冊(cè)一個(gè)自定義線程池(也有可能不是自定義的,直接使用更不推薦Executors 創(chuàng)建的線程池),也許是業(yè)務(wù)量不高、也許是其他原因,反正全局可這一個(gè)線程池使勁造。5dw28資訊網(wǎng)——每日最新資訊28at.com

5dw28資訊網(wǎng)——每日最新資訊28at.com

一、看個(gè)代碼

業(yè)務(wù)邏輯代碼:5dw28資訊網(wǎng)——每日最新資訊28at.com

5dw28資訊網(wǎng)——每日最新資訊28at.com

自定義線程池 BizThreadPool 代碼如下:5dw28資訊網(wǎng)——每日最新資訊28at.com

5dw28資訊網(wǎng)——每日最新資訊28at.com

通過上方的代碼示例,如果你還沒有看出問題,那你可以停留幾秒思考一下。5dw28資訊網(wǎng)——每日最新資訊28at.com

自定義線程池創(chuàng)建,使用的這個(gè)隊(duì)列,嗯......,大家工作中一定不要這么用,此處只是為了做演示使用。5dw28資訊網(wǎng)——每日最新資訊28at.com

5dw28資訊網(wǎng)——每日最新資訊28at.com

如果你已經(jīng)看出來了問題所在,也希望你能繼續(xù)看下去,驗(yàn)證一下咱們是不是想的相同。5dw28資訊網(wǎng)——每日最新資訊28at.com

二、有啥問題

經(jīng)過短暫幾秒鐘的思考之后,決定還是運(yùn)行一下 Demo 看看現(xiàn)象。5dw28資訊網(wǎng)——每日最新資訊28at.com

封裝一個(gè) controller 直接啟動(dòng) Springboot 程序,Java 啟動(dòng)。5dw28資訊網(wǎng)——每日最新資訊28at.com

5dw28資訊網(wǎng)——每日最新資訊28at.com

啟動(dòng)成功之后調(diào)用 GET http://localhost:8080/test/test,輸出結(jié)果如下。5dw28資訊網(wǎng)——每日最新資訊28at.com

5dw28資訊網(wǎng)——每日最新資訊28at.com

5dw28資訊網(wǎng)——每日最新資訊28at.com

按照我們的預(yù)期,日志中應(yīng)該也要輸出子任務(wù)才對(duì)啊,怎么創(chuàng)建的子任務(wù)沒有輸出呢,看現(xiàn)象應(yīng)該是沒有執(zhí)行。5dw28資訊網(wǎng)——每日最新資訊28at.com

那我們先執(zhí)行一下 jstack 命令看一下線程相關(guān)的信息,輸出信息中其中一段如下所示。5dw28資訊網(wǎng)——每日最新資訊28at.com

5dw28資訊網(wǎng)——每日最新資訊28at.com

5dw28資訊網(wǎng)——每日最新資訊28at.com

通過上面的堆棧信息可以看出,主線程在將父任務(wù)執(zhí)行完成之后,開啟了一個(gè)CountDownLatch并等待3個(gè)子任務(wù)執(zhí)行完成。5dw28資訊網(wǎng)——每日最新資訊28at.com

問題就在這,一直等待,一直等不到結(jié)果,所以就是我們剛開始看到的結(jié)果,只有父任務(wù)執(zhí)行了,子任務(wù)并沒有執(zhí)行。5dw28資訊網(wǎng)——每日最新資訊28at.com

一次調(diào)用沒有響應(yīng),多次調(diào)用之后,達(dá)到服務(wù)器資源瓶頸時(shí)系統(tǒng)就該發(fā)生崩潰了。5dw28資訊網(wǎng)——每日最新資訊28at.com

5dw28資訊網(wǎng)——每日最新資訊28at.com

那么子任務(wù)為何沒有執(zhí)行到呢?5dw28資訊網(wǎng)——每日最新資訊28at.com

三、小試牛刀

首先我們從頭開始捋一下,先看下線程池的配置。5dw28資訊網(wǎng)——每日最新資訊28at.com

5dw28資訊網(wǎng)——每日最新資訊28at.com

5dw28資訊網(wǎng)——每日最新資訊28at.com

我們?cè)趧?chuàng)建自定義線程池時(shí),核心線程與最大線程都設(shè)置的1,那我們直接修改最大線程數(shù)量,讓線程池有線程可以執(zhí)行子任務(wù)不就行了嗎?5dw28資訊網(wǎng)——每日最新資訊28at.com

5dw28資訊網(wǎng)——每日最新資訊28at.com

對(duì)于生產(chǎn)中,核心線程與最大線程一般也不會(huì)設(shè)置為1,但是哪怕你設(shè)置為10、100、1000,極端情況下也會(huì)出現(xiàn)本文后面將要講述的問題。5dw28資訊網(wǎng)——每日最新資訊28at.com

5dw28資訊網(wǎng)——每日最新資訊28at.com

5dw28資訊網(wǎng)——每日最新資訊28at.com

說干就干,創(chuàng)建自定義線程池的代碼變?yōu)榱巳缦滦问健?span style="display:none">5dw28資訊網(wǎng)——每日最新資訊28at.com

5dw28資訊網(wǎng)——每日最新資訊28at.com

5dw28資訊網(wǎng)——每日最新資訊28at.com

非常自信的你重啟程序,然后調(diào)用接口,最終傻眼了,怎么沒變化?5dw28資訊網(wǎng)——每日最新資訊28at.com

如果你修改完最大線程數(shù)就去重啟程序的話,說明線程池的工作原理你已經(jīng)忘了!5dw28資訊網(wǎng)——每日最新資訊28at.com

好吧原諒你了,這次不準(zhǔn)再忘了,下面跟我一起來看看這究竟是什么原因。5dw28資訊網(wǎng)——每日最新資訊28at.com

5dw28資訊網(wǎng)——每日最新資訊28at.com

四、線程池工作流程

這里放一下線程池的工作流程。5dw28資訊網(wǎng)——每日最新資訊28at.com

面試官:線程池核心線程設(shè)置為0時(shí)任務(wù)執(zhí)行流程怎么樣的5dw28資訊網(wǎng)——每日最新資訊28at.com

5dw28資訊網(wǎng)——每日最新資訊28at.com

5dw28資訊網(wǎng)——每日最新資訊28at.com

5dw28資訊網(wǎng)——每日最新資訊28at.com

5dw28資訊網(wǎng)——每日最新資訊28at.com

知道了線程池的工作流程之后,在上述代碼中,哪怕增加了最大線程池的數(shù)量,最終子任務(wù)也并不會(huì)執(zhí)行到,我們可以打印一下當(dāng)前線程池的狀態(tài)進(jìn)行輔助觀察。(上述代碼的printThreadPoolStatus()方法會(huì)進(jìn)行線程池當(dāng)前狀態(tài)的打印)5dw28資訊網(wǎng)——每日最新資訊28at.com

調(diào)用一下GET http://localhost:8080/test/info方法查看線程池當(dāng)前的狀態(tài)。5dw28資訊網(wǎng)——每日最新資訊28at.com

5dw28資訊網(wǎng)——每日最新資訊28at.com

5dw28資訊網(wǎng)——每日最新資訊28at.com

可以看到隊(duì)列中存在3個(gè)任務(wù)在排隊(duì),等待線程池分配線程執(zhí)行任務(wù)。這也就是修改了最大線程池?cái)?shù)量未生效的原因,因?yàn)檫€有一個(gè)無界隊(duì)列。5dw28資訊網(wǎng)——每日最新資訊28at.com

當(dāng)然如果任務(wù)一直增加,隊(duì)列中任務(wù)數(shù)量越來越多,達(dá)到服務(wù)器的瓶頸,就會(huì)發(fā)生OOM了。(阿里開發(fā)規(guī)范中不推薦使用無界隊(duì)列的原因)5dw28資訊網(wǎng)——每日最新資訊28at.com

五、修改核心線程數(shù)量

那我們直接修改核心線程數(shù)量吧,核心線程超過任務(wù)數(shù)量?5dw28資訊網(wǎng)——每日最新資訊28at.com

回答:不行。5dw28資訊網(wǎng)——每日最新資訊28at.com

5dw28資訊網(wǎng)——每日最新資訊28at.com

對(duì)于我們上面的例子來說,增加核心線程數(shù)量,擁有可以執(zhí)行子任務(wù)的線程,確實(shí)可以解決當(dāng)下場(chǎng)景。5dw28資訊網(wǎng)——每日最新資訊28at.com

但是當(dāng)并發(fā)量上來之后,或者說線程池的線程都被父線程所占用時(shí),依舊會(huì)發(fā)現(xiàn)子任務(wù)無法獲得線程執(zhí)行。5dw28資訊網(wǎng)——每日最新資訊28at.com

此處我們修改核心線程為10執(zhí)行看一下輸出結(jié)果。5dw28資訊網(wǎng)——每日最新資訊28at.com

5dw28資訊網(wǎng)——每日最新資訊28at.com

5dw28資訊網(wǎng)——每日最新資訊28at.com

通過修改核心線程數(shù)量,解決了子任務(wù)在隊(duì)列中堆積的問題。5dw28資訊網(wǎng)——每日最新資訊28at.com

所以通過上述代碼,大家應(yīng)該知道死鎖是怎么發(fā)生的了吧,這里我總結(jié)一下。5dw28資訊網(wǎng)——每日最新資訊28at.com

六、小結(jié)

當(dāng)核心線程為1,最大線程為1,使用無界隊(duì)列。父任務(wù)在線程中等待子任務(wù)完成的通知,子任務(wù)在線程池的任務(wù)隊(duì)列中等待線程池調(diào)度線程資源。5dw28資訊網(wǎng)——每日最新資訊28at.com

5dw28資訊網(wǎng)——每日最新資訊28at.com

當(dāng)核心線程為1,最大線程為n,使用無界隊(duì)列。最大線程設(shè)置n與設(shè)置1沒有區(qū)別,除非使用的隊(duì)列不同,只要是使用的無界隊(duì)列,當(dāng)資源耗盡之時(shí),就是服務(wù)崩潰的時(shí)候。此時(shí)后面新的父任務(wù)到來時(shí),也只會(huì)在任務(wù)隊(duì)列中繼續(xù)堆積。5dw28資訊網(wǎng)——每日最新資訊28at.com

5dw28資訊網(wǎng)——每日最新資訊28at.com

當(dāng)核心線程為n,最大線程為n,使用無界隊(duì)列。核心線程設(shè)置為n,意味著父線程大概率是可以執(zhí)行的,創(chuàng)建的子任務(wù)在任務(wù)隊(duì)列中排隊(duì)執(zhí)行。5dw28資訊網(wǎng)——每日最新資訊28at.com

5dw28資訊網(wǎng)——每日最新資訊28at.com

當(dāng)并發(fā)量上來,或者核心線程都被父任務(wù)所占據(jù)之后,線程池調(diào)用就變成了如下場(chǎng)景,所有的任務(wù)都被堆積在任務(wù)隊(duì)列當(dāng)中:5dw28資訊網(wǎng)——每日最新資訊28at.com

5dw28資訊網(wǎng)——每日最新資訊28at.com

5dw28資訊網(wǎng)——每日最新資訊28at.com

核心線程全是父任務(wù),后面創(chuàng)建的任務(wù)也都在任務(wù)隊(duì)列堆積,最終達(dá)到服務(wù)器瓶頸系統(tǒng)OOM。5dw28資訊網(wǎng)——每日最新資訊28at.com

七、最終解決方案

通過上述代碼示例,死鎖的根本原因在于,父任務(wù)會(huì)創(chuàng)建多個(gè)子任務(wù),并等待子任務(wù)執(zhí)行結(jié)束,而父子任務(wù)都是使用的同一個(gè)線程池,當(dāng)線程池中執(zhí)行線程都是父任務(wù)時(shí),所有的子任務(wù)又都在任務(wù)隊(duì)列中等待執(zhí)行,所以這樣就會(huì)發(fā)生死鎖。5dw28資訊網(wǎng)——每日最新資訊28at.com

核心線程永遠(yuǎn)不會(huì)釋放,從而造成任務(wù)隊(duì)列不斷堆積,直到OOM。5dw28資訊網(wǎng)——每日最新資訊28at.com

5dw28資訊網(wǎng)——每日最新資訊28at.com

5dw28資訊網(wǎng)——每日最新資訊28at.com

所以解決方案就是,隔離線程池。5dw28資訊網(wǎng)——每日最新資訊28at.com

不同的業(yè)務(wù)使用不同的線程池,使用一個(gè)新的線程池處理子任務(wù),這樣就可以避免死鎖的發(fā)生了。5dw28資訊網(wǎng)——每日最新資訊28at.com

修改之后的代碼如下。5dw28資訊網(wǎng)——每日最新資訊28at.com

5dw28資訊網(wǎng)——每日最新資訊28at.com

5dw28資訊網(wǎng)——每日最新資訊28at.com

通過查看日志輸出可以發(fā)現(xiàn),線程池隔離之后,哪怕核心線程設(shè)置為1,也是可以正常執(zhí)行業(yè)務(wù)邏輯的,任務(wù)隊(duì)列中也沒有堆積任務(wù)。5dw28資訊網(wǎng)——每日最新資訊28at.com

八、總結(jié)

通過上面的 Demo 復(fù)現(xiàn)以及解決方案,在工作中優(yōu)化建議如下:5dw28資訊網(wǎng)——每日最新資訊28at.com

  • 禁止使用Executors創(chuàng)建自定義線程池。使用ThreadPoolExecutor創(chuàng)建線程池時(shí),注意每個(gè)參數(shù)的含義,規(guī)避資源耗盡的風(fēng)險(xiǎn)。
  • 線程池使用有界隊(duì)列,避免使用無界隊(duì)列。
  • 對(duì)于父子任務(wù)的場(chǎng)景,可以使用線程池或者 MQ。使用有界隊(duì)列之后,制定合理的拒絕策略,拒絕策略可以考慮 MQ 做重試。
  • 不同業(yè)務(wù)使用不同的線程池,禁止父子任務(wù)使用相同的線程池。

本文鏈接:http://www.www897cc.com/showinfo-26-112764-0.html不同業(yè)務(wù)使用同一個(gè)線程池發(fā)生死鎖

聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com

上一篇: Python必知必會(huì):15個(gè)令人相見恨晚的Python字符串格式化技巧!

下一篇: 玩轉(zhuǎn)文件權(quán)限:Python 的七個(gè)權(quán)限操作實(shí)戰(zhàn)

標(biāo)簽:
  • 熱門焦點(diǎn)
Top 主站蜘蛛池模板: 雅安市| 海兴县| 巫溪县| 宁都县| 陆丰市| 焦作市| 湛江市| 宜兰市| 衡阳市| 黑河市| 江西省| 平顺县| 盱眙县| 岳普湖县| 嘉黎县| 东乡族自治县| 石棉县| 砚山县| 平凉市| 广德县| 洪江市| 十堰市| 泰顺县| 深圳市| 海淀区| 巴青县| 库尔勒市| 九龙县| 哈尔滨市| 东辽县| 衡阳县| 巴里| 息烽县| 云林县| 冷水江市| 和田县| 汶川县| 英超| 天峻县| 凭祥市| 德惠市|