使用Java無界隊列的線程池會怎么樣

本篇內(nèi)容主要講解“使用Java無界隊列的線程池會怎么樣”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“使用Java無界隊列的線程池會怎么樣”吧!

廣德ssl適用于網(wǎng)站、小程序/APP、API接口等需要進行數(shù)據(jù)傳輸應(yīng)用場景,ssl證書未來市場廣闊!成為創(chuàng)新互聯(lián)的ssl證書銷售渠道,可以享受市場價格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:13518219792(備注:SSL證書合作)期待與您的合作!

(1)背景引入

今天跟大家聊一個互聯(lián)網(wǎng)大廠的Java面試題:使用無界隊列的線程池會導(dǎo)致內(nèi)存飆升嗎?

因為在面互聯(lián)網(wǎng)大廠的時候,一定會問并發(fā),問并發(fā)的時候一定會問到線程池,問到線程池一定會問構(gòu)造線程池的一些參數(shù)的含義。

然后,有一些面試官會就線程池的具體場景,問一些可能會遇到的問題。

所以,在這里就可能有上述那樣一個面試中的問題,算是Java面試里相對來說高階一點的。

我相信大家一定起碼知道線程池是個什么東西的。簡單來說,就是維護一個池子,池子里面放了很多的線程。

然后來一個任務(wù),某個線程就獲取這個任務(wù)來執(zhí)行,任務(wù)執(zhí)行完之后線程是不會釋放掉的,而是停留在線程池里繼續(xù)等待下一個任務(wù)。

這樣的一個好處是你沒必要自己手動頻繁的創(chuàng)建和銷毀線程,畢竟線程是較重的資源,頻繁的創(chuàng)建和銷毀對系統(tǒng)性能是沒好處的。

我們看看下面的圖,回顧一下線程池的含義。

使用Java無界隊列的線程池會怎么樣

(2)線程池是如何構(gòu)造的?

那么平時在Java里寫代碼的時候,大家記得不記得線程池是如何構(gòu)造出來的呢?

是不是類似下面那樣的代碼,比如說我們構(gòu)造一個線程數(shù)量固定的一個線程池:

使用Java無界隊列的線程池會怎么樣

那么Executors.newFixedThreadPool(10)內(nèi)部到底又是如何構(gòu)造出來線程池的呢?

其實很簡單,翻開JDK源碼就可以看到里面的代碼如下:

使用Java無界隊列的線程池會怎么樣

簡單來說,就是構(gòu)造了一個ThreadPoolExecutor對象實例,你大致就認為他是一個線程池吧,傳入了一些參數(shù),這些參數(shù)大致包含了:

  1  ·   corePoolSize

  2  ·   maximumPoolSize

  3  ·   keepAliveTime

  4  · workQueue

假如說我們構(gòu)造線程池傳入的線程數(shù)量是10,那么在這里,corePoolSize和maximumSize都是10,keepAliveTime默認就是0,workQueue是一個無界的LinkedBlockingQueue。

接下來,我們具體來看看構(gòu)造一個線程池傳入一些參數(shù)之后,具體這個線程池的運行原理是什么。

(3)線程池的運行原理

簡單來說,剛開始的時候其實線程池里是空的,就是一個線程都沒有的,如下圖所示。

使用Java無界隊列的線程池會怎么樣

接著如果你使用線程池提交一個任務(wù)進去,希望由線程池里的一個線程來執(zhí)行,如下代碼所示,就是提交一個任務(wù):

使用Java無界隊列的線程池會怎么樣

這個時候,線程池會先看一下,現(xiàn)在池子里的線程數(shù)量有沒有有達到corePoolSize指定的數(shù)量。

現(xiàn)在線程池里的線程數(shù)量是0,然后corePoolSize是10,那么肯定沒達到了,所以直接會在線程池里創(chuàng)建一個線程出來然后執(zhí)行這個任務(wù),如下圖。

使用Java無界隊列的線程池會怎么樣

接著假如說,這個線程處理完一個任務(wù)了,那么此時線程是不會被銷毀的,他會一直等待下一個提交過來的任務(wù)。

那么,到底是怎么等待的呢?

很簡單,線程池會搭配一個workQueue,比如這里搭配的就是一個無界的LinkedBlockingQueue,幾乎可以無限量放入任務(wù)。

然后那個線程處理完一個任務(wù)之后,就會用阻塞的方式嘗試從任務(wù)隊列里獲取任務(wù),如果隊列是空的,他就會阻塞卡在那兒不動,直到有人放一個任務(wù)到隊列里,他才會獲取到一個任務(wù)然后繼續(xù)執(zhí)行,循環(huán)往復(fù),如下圖。

使用Java無界隊列的線程池會怎么樣

接著再次提交任務(wù),線程池一判斷發(fā)現(xiàn),誒?好像線程數(shù)量才只有1個,完全比corePoolSize(10個)要小,那么繼續(xù)直接在池子里創(chuàng)建一個線程,然后處理這個任務(wù),處理完了繼續(xù)嘗試從workQueue里阻塞式獲取任務(wù)。

一直重復(fù)上面的操作,直到線程池里有10個線程了,達到了corePoolSize指定的數(shù)量,如下圖。

使用Java無界隊列的線程池會怎么樣

這個時候你如果再提交任務(wù),他一下子發(fā)現(xiàn),誒?不對啊,線程池里已經(jīng)有10個線程了,跟corePoolSize指定的線程數(shù)量一樣了。

那么現(xiàn)在,我就不需要創(chuàng)建任何一個額外的線程了,現(xiàn)在你只要提交任務(wù),全部直接入隊到workQueue里就好。

此時線程池里的線程都阻塞式在workQueue上等待獲取任務(wù),有一個任務(wù)進來就會喚醒一個線程來處理這個任務(wù),處理完了任務(wù)再次阻塞在workQueue上嘗試獲取下一個任務(wù),如下圖所示這個意思。

使用Java無界隊列的線程池會怎么樣

這里我們看到他用的是一個無界的LinkedBlockingQueue,但是假如說他用的是一個有界的隊列呢?

比如說限定好了隊列最多只能放10個任務(wù),那么假如說,線程池里的線程來不及處理任務(wù)了,然后隊列一下子放滿了10個任務(wù)。

此時就會出現(xiàn)任務(wù)入隊的失敗,因為隊列滿了,無法入隊。

然后就會嘗試再次在線程池里創(chuàng)建線程,這個時候就會一直創(chuàng)建線程直到線程池里的線程數(shù)量達到maximumPoolSize指定的數(shù)量為止。

雖然這里fixed線程池默認corePoolSize和maximumPoolSize的數(shù)量都是一致的,但是可以假設(shè)此時maximumPoolSize的數(shù)量是20呢?

那么就會繼續(xù)創(chuàng)建線程,直到線程數(shù)量達到20個,然后用額外創(chuàng)建的10個線程在隊列滿的情況下,繼續(xù)處理任務(wù)。

整個過程,如下圖所示:

使用Java無界隊列的線程池會怎么樣

接著萬一隊列滿了,然后線程池的線程數(shù)量達到了maximumPoolSize指定的數(shù)量了,你額外創(chuàng)建線程都無法創(chuàng)建了,此時會如何呢?

答案是:會reject掉,不讓你繼續(xù)提交任務(wù)了,此時默認的就是拋出一個異常。

那么,在上圖中額外創(chuàng)建出來的,超出corePoolSize的那些線程呢?

他們一旦創(chuàng)建出來之后,會發(fā)現(xiàn)線程池數(shù)量已經(jīng)超過corePoolSize了,此時他們會嘗試等待workQueue里的任務(wù)。

一旦超過keepAliveTime指定的時間,還獲取不到任務(wù),比如keepAliveTime是60秒,那么假如超過60秒獲取不到任務(wù),他就會自動釋放掉了,這個線程就銷毀了。

整個過程,如下圖所示。

使用Java無界隊列的線程池會怎么樣

(4)無界隊列引發(fā)的內(nèi)存飆升

明白了線程池的運行原理了,這個面試題就好解答了。

我們以最常用的fixed線程池舉例,他的線程池數(shù)量是固定的,因為他用的是近乎于無界的LinkedBlockingQueue,幾乎可以無限制的放入任務(wù)到隊列里。

所以只要線程池里的線程數(shù)量達到了corePoolSize指定的數(shù)量之后,接下來就維持這個固定數(shù)量的線程了。

然后,所有任務(wù)都會入隊到workQueue里去,線程從workQueue獲取任務(wù)來處理。

這個隊列幾乎永遠不會滿,當然這是幾乎,因為LinkedBlockingQueue默認的最大任務(wù)數(shù)量是Integer.MAX_VALUE,非常大,近乎于可以理解為無限吧。

只要隊列不滿,就跟maximumPoolSize、keepAliveTime這些沒關(guān)系了,因為不會創(chuàng)建超過corePoolSize數(shù)量的線程的。

同樣,給大家來一張圖,我們來看看:

使用Java無界隊列的線程池會怎么樣

那么此時萬一每個線程獲取到一個任務(wù)之后,他處理的時間特別特別的長,長到了令人發(fā)指的地步。比如處理一個任務(wù)要幾個小時,此時會如何?

當然會出現(xiàn)workQueue里不斷的積壓越來越多得任務(wù),不停的增加。

這個過程中會導(dǎo)致機器的內(nèi)存使用不停的飆升,最后也許極端情況下就導(dǎo)致JVM OOM了,系統(tǒng)就掛掉了。

所以這就是這個面試題背后你要知道的線程池的運行原理,以及可能遇到的一些問題,大家要做到心里有數(shù)。

到此,相信大家對“使用Java無界隊列的線程池會怎么樣”有了更深的了解,不妨來實際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進入相關(guān)頻道進行查詢,關(guān)注我們,繼續(xù)學習!

當前文章:使用Java無界隊列的線程池會怎么樣
URL標題:http://muchs.cn/article14/gehdde.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供Google、云服務(wù)器、關(guān)鍵詞優(yōu)化移動網(wǎng)站建設(shè)、品牌網(wǎng)站制作、網(wǎng)站收錄

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

外貿(mào)網(wǎng)站建設(shè)