久久午夜无码,国产中文资源,Chinese熟女熟妇2乱2,高清五码d一区

線程池的工作原理(一文詳解線程池的工作原理)

線程池的工作原理(一文詳解線程池的工作原理)

尚念夢 2025-04-15 科技 54 次瀏覽 0個評論

在工作中或多或少都使用過線程池。但是為什么要使用線程池呢?從它的名稱中我們就可以猜到,線程池是使用了一種池化技術(shù)(Pooling Technology)。和很多其他池化技術(shù)一樣,都是為了更高效的利用資源,例如連接池,內(nèi)存池等。

數(shù)據(jù)庫連接是一種很昂貴的資源,創(chuàng)建和銷毀都需要付出高昂的代價。為了避免頻繁地創(chuàng)建數(shù)據(jù)庫連接,所以產(chǎn)生了數(shù)據(jù)庫連接池技術(shù)。優(yōu)先在池子中創(chuàng)建一批數(shù)據(jù)庫連接,當(dāng)有需要訪問數(shù)據(jù)庫時,直接到池子中去獲取一個可用的連接,使用完了之后再歸還到連接池中去。

同樣的,線程也是一種很寶貴的資源,并且也是一種有限的資源,創(chuàng)建和銷毀線程也同樣需要付出不菲的代價。我們所有的代碼執(zhí)行都是由一個一個的線程支撐起來的,如今的芯片架構(gòu)也決定了我們必須編寫多線程執(zhí)行的程序,以獲得最高的程序性能。那么怎樣高效地管理多線程之間的分工與協(xié)作就成了一個關(guān)鍵問題,Doug Lea大神為我們設(shè)計并實現(xiàn)了一款線程池工具,通過該工具就可以實現(xiàn)多線程的能力,并實現(xiàn)任務(wù)的高效執(zhí)行與調(diào)度。為了正確合理地使用線程池工具,我們有必要對線程池的原理進(jìn)行了解。

了解線程池工作原理主要有三個方面:線程池狀態(tài)、線程池的重要屬性和線程池的工作流程。

線程池狀態(tài)

線程池是有狀態(tài)的,這些狀態(tài)標(biāo)識這個線程池內(nèi)部的一些運(yùn)行情況。線程池的開啟到關(guān)閉的過程就是線程池狀態(tài)的一個流轉(zhuǎn)過程。

線程池共有5種狀態(tài):

一文詳解線程池的工作原理

運(yùn)行狀態(tài)(RUNNING):此狀態(tài)下,線程池可以接受新的任務(wù),也可以處理阻塞隊列中的任務(wù)。執(zhí)行shutdown()方法可進(jìn)入待關(guān)閉(SHUTDOWN)狀態(tài),執(zhí)行shutdownNow()方法可進(jìn)入停止(STOP)狀態(tài)。待關(guān)閉狀態(tài)(SHUTDOWN):此狀態(tài)下,線程池不再接受新的任務(wù),繼續(xù)處理阻塞隊列中的任務(wù)。當(dāng)阻塞隊列中的任務(wù)為空,且工作線程數(shù)為0的時候,進(jìn)入整理(TIDYING)狀態(tài)。停止?fàn)顟B(tài)(STOP):此狀態(tài)下,線程池不接受新任務(wù),也不處理阻塞隊列中的任務(wù),反而會嘗試結(jié)束執(zhí)行中的任務(wù)。當(dāng)工作線程數(shù)為0時,進(jìn)入整理(TIDYING)狀態(tài)。整理狀態(tài)(TIDYING):此狀態(tài)下,所有任務(wù)都已經(jīng)執(zhí)行完畢,且沒有工作線程。執(zhí)行terminated()方法進(jìn)入終止(TERMINATED)狀態(tài)。終止?fàn)顟B(tài)(TERMINATED):此狀態(tài)下,線程池完全終止,并完成了所有資源的釋放。線程池的重要屬性

一個線程池的核心參數(shù)有很多,每個參數(shù)都有著特殊的作用,各個參數(shù)聚合再一起后將完成整個線程池的完整工作。其中的六個尤為重要:線程狀態(tài)和工作線程的數(shù)量,核心線程數(shù)和最大線程數(shù),創(chuàng)建線程的工廠,緩存任務(wù)的阻塞隊列,非核心線程存活的時間和拒絕策略。

線程狀態(tài)和工作線程數(shù)量

首先線程池是有狀態(tài)的,在不同的狀態(tài)下,線程池的行為是不一樣的。

然后線程池肯定是需要線程去執(zhí)行具體的任務(wù),所以在線程池中就封裝了一個內(nèi)部類Worker作為工作線程,每個Worker中都維持著一個Thread。

線程池的重點之一,就是控制線程資源合理高效的使用,所以必須控制工作線程的個數(shù),所以需要保存當(dāng)前線程池中工作線程的個數(shù)。

看到這里,你是否覺得需要用兩個變量來保存線程池的狀態(tài)和線程池中工作線程的個數(shù)呢?但是在ThreadPoolExecutor中只用了一個AtomicInteger型的變量就保存了這兩個屬性的值,那就是ctl。

一文詳解線程池的工作原理

ctl是一個原子操作類型(AtomicInteger)的變量。ctl的高3位用來表示線程池的狀態(tài)(runState),低29位用來表示工作線程的個數(shù)(workerCnt)。為什么要用3位來表示線程池的狀態(tài)呢,原因是因為線程池一共有5種狀態(tài),而2位只能表示出4種情況(2位是2^2,最多產(chǎn)生4種結(jié)果),至少需要3位才能表示得了全部的5種狀態(tài)(3位是3^2,最多產(chǎn)生9種結(jié)果)。

核心線程數(shù)和最大線程數(shù)

現(xiàn)在有了標(biāo)識工作線程的個數(shù)的變量了,那到底該有多少個線程才合適呢?線程多了會浪費(fèi)線程資源,少了又不能發(fā)揮線程池的性能。

為了解決這個問題,線程池設(shè)計了兩個變量來協(xié)作,分別是:

核心線程數(shù)(corePoolSize):用來表示線程池中的核心線程的數(shù)量,也可以稱為可閑置的線程數(shù)量。

最大線程數(shù)(maximumPoolSize):用來表示線程池中最多能夠創(chuàng)建的線程數(shù)量。

現(xiàn)在我們有一個疑惑,既然已經(jīng)有了標(biāo)識工作線程的個數(shù)的變量了,為什么還要有核心線程數(shù)和最大線程數(shù)呢?

其實你這樣想就能夠理解了,創(chuàng)建線程是有代價的,不能每次要執(zhí)行一個任務(wù)時就創(chuàng)建一個線程,但是也不能在任務(wù)非常多的時候,只有少量的線程在執(zhí)行,這樣任務(wù)是來不及處理的,而是應(yīng)該創(chuàng)建合適的足夠多的線程來及時地處理任務(wù)。

隨著任務(wù)數(shù)量的變化,當(dāng)任務(wù)數(shù)量明顯減少時,原本創(chuàng)建的多余的線程就沒有必要再存活著了,因為這時使用少量的線程就能夠處理得過來了,所以說真正工作的線程的數(shù)量,是隨著任務(wù)的變化而變化的。

那核心線程數(shù)和最大線程數(shù)和工作線程個數(shù)的關(guān)系是什么呢?

一文詳解線程池的工作原理

工作線程的個數(shù)可能從0到最大線程數(shù)之間變化,當(dāng)執(zhí)行一段時間之后可能維持在核心線程數(shù)(corePoolSize),但也不是絕對的,取決于核心線程是否允許被超時回收。

創(chuàng)建線程的工廠

既然是線程池,那自然少不了線程。線程該如何來創(chuàng)建呢?這個任務(wù)就交給了線程工廠ThreadFactory來完成。

緩存任務(wù)的阻塞隊列

上面我們說了核心線程數(shù)和最大線程數(shù),并且也介紹了工作線程的個數(shù)是在0和最大線程數(shù)之間變化的。但是不可能一下子就創(chuàng)建了所有線程,把線程池裝滿,而是有一個過程:

當(dāng)線程池接受到一個任務(wù)時,如果工作線程數(shù)沒有達(dá)到corePoolSize,那么就會新建一個線程,并綁定該任務(wù),知道工作線程的數(shù)量達(dá)到corePoolSize前都不會重用之前創(chuàng)建的線程。

當(dāng)工作線程數(shù)達(dá)到corePoolSize了,這是又接收到新任務(wù)時,會將任務(wù)存放在一個阻塞隊列(workQueue)中等待核心線程去執(zhí)行。為什么不直接創(chuàng)建更多的線程來執(zhí)行新任務(wù)呢?原因是核心線程中很可能已經(jīng)有線程執(zhí)行完自己的任務(wù)了,或者有其他線程馬上就能處理完當(dāng)前的任務(wù),并且接下來就能投入到新的任務(wù)中去,所以阻塞隊列是一種緩沖機(jī)制,給核心線程一個機(jī)會讓他們充分發(fā)揮自己的能力。另外一個值得考慮的原因是,創(chuàng)建線程畢竟是代價昂貴的,不可能一有任務(wù)要執(zhí)行就去創(chuàng)建一個新的線程。

所以我們需要為線程池配備一個阻塞隊列,用來臨時緩存任務(wù),這些任務(wù)將等待工作線程來執(zhí)行。

一文詳解線程池的工作原理

非核心線程存活時間

上面我們說了,當(dāng)工作線程數(shù)達(dá)到corePoolSize時,線程池會將新接收到的任務(wù)放在阻塞隊列中,而阻塞隊列又分為兩種情況:一種是有界的隊列,一種是無界的隊列。

如果是無界隊列,那么當(dāng)核心線程都在忙時,所有新提交的任務(wù)都會被存放在該無界隊列中,這時最大線程數(shù)將變得沒有意義,因為阻塞隊列不會存在被裝滿的情況。

如果是有界隊列,那么當(dāng)阻塞隊列中裝滿了等待執(zhí)行的任務(wù),這時再有新任務(wù)提交時,線程池就需要創(chuàng)建新的臨時線程來處理,相當(dāng)于增派人手來處理任務(wù)。

但是創(chuàng)建的臨時線程是有存活時間的,不可能讓它們一直都存活著,當(dāng)阻塞隊列中的任務(wù)被執(zhí)行完畢,并且又沒有那么多新任務(wù)被提交時,臨時線程就需要被回收銷毀,而在被回收銷毀之前等待的這段時間,就是非核心線程的存活時間,也就是keepAliveTime屬性。

那么什么是非核心線程呢?是不是先創(chuàng)建的線程就是核心線程,后創(chuàng)建的就是非核心線程呢?

其實核心線程跟創(chuàng)建的先后沒有關(guān)系,而是跟工作線程的個數(shù)有關(guān),如果當(dāng)前工作線程的個數(shù)大于核心線程數(shù),那么所有的線程都可能是非核心線程,都有被回收的可能。

一個線程執(zhí)行完一個任務(wù)后,會去阻塞隊列里面取新的任務(wù),在取到任務(wù)之前,它就是一個閑置的線程。

取任務(wù)的方法有兩種,一種是通過take()方法一直阻塞直到取出任務(wù),另一種是通過poll(keepAliveTime, timeUnit)方法在一定時間內(nèi)取出任務(wù)或者超時,如果超時這個線程就會被回收,請注意核心線程一般不會被回收。

那么怎么保證核心線程不會被回收呢?還是跟工作線程的個數(shù)有關(guān),每一個線程在取任務(wù)的時候,線程池會比較當(dāng)前的工作線程個數(shù)與核心線程數(shù)。

如果工作線程數(shù)小于當(dāng)前的核心線程數(shù),則使用第一種方法取任務(wù),也就是沒有超時回收,這時所有的工作線程都是核心線程,它們不會被回收。如果工作線程數(shù)大于核心線程數(shù),則使用第二種方法取任務(wù),一旦超時就回收,所以并沒有絕對的核心線程,只要這個線程沒有在存活時間內(nèi)取到任務(wù)去執(zhí)行就會被回收。

所以每個線程如果想要保住自己核心線程的身份,必須充分努力,盡可能快得獲取到任務(wù)去執(zhí)行,這樣才能避免被回收的命運(yùn)。

核心線程一般不會被回收,但是也不是絕對的,如果我們設(shè)置了允許核心線程超時被回收的話,那么就沒有核心線程這種說法了,所有的線程都會通過poll(keepAliveTime, timeUnit)來獲取任務(wù),一旦超時獲取不到任務(wù),就會被回收,一般很少會這樣來使用,除非該線程池需要處理的任務(wù)非常少,并且頻率也不高,不需要將核心線程一直維持著。

拒絕策略

雖然我們有了阻塞隊列來對任務(wù)進(jìn)行緩存,從一定程度上為線程池的執(zhí)行提供了緩沖期,但是如果是有界的阻塞隊列,那就存在隊列滿的情況,也存在工作線程的數(shù)據(jù)已經(jīng)達(dá)到最大線程數(shù)的時候。如果這時候再有新的任務(wù)提交時,顯然線程池已經(jīng)心有余而力不足了,因為既沒有空余的隊列空間來存放該任務(wù),也無法創(chuàng)建新的線程來執(zhí)行該任務(wù)了,所以這時我們就需要有一種拒絕策略,即handler。

拒絕策略是一個RejectedExecutionHandler類型的變量,用戶可以自行指定拒絕的策略,如果不指定的話,線程池將使用默認(rèn)的拒絕策略:拋出異常。

在線程池中還為我們提供了很多其他可以選擇的拒絕策略:

直接丟棄該任務(wù)使用調(diào)用者線程執(zhí)行該任務(wù)丟棄任務(wù)隊列中的最老的一個任務(wù),然后提交該任務(wù)工作流程

了解了線程池中所有的重要屬性之后,現(xiàn)在我們需要來了解下線程池的工作流程了。

一文詳解線程池的工作原理

上面是一張線程池工作的精簡圖,實際的過程要比這個復(fù)雜得多,但是這些應(yīng)該能夠完全覆蓋到線程池的整個工作流程了。

整個過程可以拆分成以下幾個部分:

提交任務(wù)

當(dāng)向線程池提交一個新的任務(wù)時,線程池有三種處理情況,分別是:創(chuàng)建一個工作線程來執(zhí)行該任務(wù)、將任務(wù)加入阻塞隊列、拒絕該任務(wù)。

提交任務(wù)的過程也可以拆分成以下幾個部分:

當(dāng)工作線程數(shù)小于核心線程數(shù)時,直接創(chuàng)建新的核心工作線程。當(dāng)工作線程數(shù)大于核心線程數(shù)時,就需要嘗試將任務(wù)添加到阻塞隊列中去。如果能夠加入成功,說明隊列還沒滿,那么就需要做以下的二次校驗來保證添加進(jìn)去的任務(wù)能夠成功被執(zhí)行。驗證當(dāng)前線程池中的運(yùn)行狀態(tài),如果是非RUNNING狀態(tài),則需要將任務(wù)從阻塞隊列中移除,然后拒絕該任務(wù)。驗證當(dāng)前線程池中的工作線程的個數(shù),如果是0,則需要主動添加一個空工作線程來執(zhí)行剛剛添加到阻塞隊列中的任務(wù)。如果加入失敗,說明隊列已經(jīng)滿了,這時就需要創(chuàng)建新的臨時工作線程來執(zhí)行任務(wù)。如果創(chuàng)建成功,則直接執(zhí)行該任務(wù)。如果創(chuàng)建失敗,說明工作線程數(shù)已經(jīng)等于最大線程數(shù)了,只能拒絕該任務(wù)了。

整個過程可以用下面這張圖來表示:

一文詳解線程池的工作原理

創(chuàng)建工作線程

創(chuàng)建工作線程需要做一系列的判斷,需要確保當(dāng)前線程池可以創(chuàng)建新的線程之后,才能創(chuàng)建。

首先,當(dāng)線程池的狀態(tài)是SHUTDOWN或者STOP時,不能創(chuàng)建新的線程。其次,當(dāng)線程工廠創(chuàng)建線程失敗時,也不能創(chuàng)建新的線程。第三,拿當(dāng)前工作線程的數(shù)量與核心線程數(shù)、最大線程數(shù)進(jìn)行比較,如果前者大于后者的話,也不允許創(chuàng)建。

除此之外,線程池會嘗試通過CAS來自增工作線程的個數(shù),如果自增成功了,則會創(chuàng)建新的工作線程,即Worker對象。

然后加鎖進(jìn)行二次驗證是否能夠創(chuàng)建工作線程,如果最后創(chuàng)建成功,則會啟動該工作線程。

啟動工作線程

當(dāng)工作線程創(chuàng)建成功后,也就是Worker對象已經(jīng)創(chuàng)建好了,這時就需要啟動該工作線程,讓線程開始干活了,Worker對象中關(guān)聯(lián)著一個Thread,所以要啟動工作線程的話,只要通過worker.thread.start()來啟動該線程即可。

啟動完了之后,就會執(zhí)行Worker對象的run方法,因為Worker實現(xiàn)了Runnable接口,所以本質(zhì)上Worker也是一個線程。

通過線程start開啟之后就會調(diào)用到Runnable的run方法,在Worker對象的run方法中,調(diào)用了runWorker(this)方法,也就是把當(dāng)前對象傳遞給了runWorker()方法,讓它來執(zhí)行。

獲取任務(wù)并執(zhí)行

在runWorker方法被調(diào)用之后,就是執(zhí)行具體的任務(wù)了,首先需要拿到一個可以執(zhí)行的任務(wù),而Worker對象中默認(rèn)綁定了一個任務(wù),如果該任務(wù)不為空的話,那么就是直接執(zhí)行。

執(zhí)行完了之后,就會去阻塞隊列中獲取任務(wù)來執(zhí)行。

獲取任務(wù)的過程則需要考慮當(dāng)前工作線程的個數(shù):

如果工作線程數(shù)大于核心線程數(shù),那么就需要通過poll(keepAliveTime, timeUnit)來獲取,因為這時需要對閑置線程進(jìn)行超時回收。如果工作線程數(shù)小于等于核心線程數(shù),那么就可以通過take()來獲取了。因為這時所有的線程都是核心線程,不需要進(jìn)行回收,前提是沒有設(shè)置allowCoreThreadTimeOut(允許核心線程超時回收)為true。source: www.cnblogs.com/yanggb/p/10629387.html

轉(zhuǎn)載請注明來自夕逆IT,本文標(biāo)題:《線程池的工作原理(一文詳解線程池的工作原理)》

每一天,每一秒,你所做的決定都會改變你的人生!

發(fā)表評論

快捷回復(fù):

評論列表 (暫無評論,54人圍觀)參與討論

還沒有評論,來說兩句吧...

四虎精品口爆颜射少妇| 野外www| 无码一区二区三区视频最新日韩| 国产成人欧美日韩综合| 情久久久| 宅宅少妇无码| 影音先锋麻豆资源| 久久亚洲一区二区| 亚洲欧美日韩综合网站色aa| 国产精品55夜色| 国产日韩Av无码免费一区二区 | 天美mv官方入口麻豆| 黄片免费看一区| 天天躁日日躁狠狠躁2018小说| 久久伊人| 97亚洲熟妇自偷自拍另类图片| 91精品福利在线| 91-区二区三区| 男女又爽 又黄| 天天色婷婷视频| 香蕉碰碰人人a久久动漫精品| JZZIJZZIJ亚洲乱熟无码| 色欧美欧洲电影综合网| 亚洲最新精选| 亚洲另类无码一区| 开心五月婷成人| 亚洲国产中文一精品综合久久| aa中文字幕在线观看| 亚洲无码一区精品免费| 国产精品视频二区二区二区色欲 | 欧美色图考逼视频| 一区2区日韩网站| 中文字幕交换系列在线| 在线观看国产自慰| 福利姬在线观看| 欧美日韩乱码香蕉视频| 国产日本淫妇人| 无码不卡色偷偷| 极品综合视频| 99久久婷婷高清精品| 日本黄色在免|