執行緒池學習理解

2021-08-14 08:46:35 字數 3102 閱讀 9502

1.執行緒池是什麼

為了避免系統頻繁地建立和銷毀執行緒,我們可以讓建立的執行緒進行復用。如果大家進行過資料庫開發,對資料庫連線池應該不會陌生。為了避免每次資料庫查詢都重新建立和銷毀資料庫連線,我們可以使用資料庫連線池維護一些資料庫連線,讓他們長期保持在乙個啟用狀態。當系統需要使用資料庫時,並不是建立乙個新的連線,而是從連線池中獲得乙個可用的連線即可。反之,當需要關閉連線時,並不真的把連線關閉,而是將這個連線「還」給連線池即可。通過這種方式,可以節約不少建立和銷毀物件的時間。

2.執行緒池的內部原理與實現

先了解一下執行緒池最重要的建構函式:

public threadpoolexecutor(int corepoolsize,

int maximumpoolsize,

long keepalivetime,

timeunit unit,

blockingqueueworkqueue,

threadfactory threadfactory,

rejectedexecutionhandler handler)

函式的引數含義如下。(如果不是太理解,可以跳過。一會回頭看會更好!)

• corepoolsize:指定了執行緒池中的執行緒數量。

• maximumpoolsize:指定了執行緒池中的最大執行緒數量。

• keepalivetime:當執行緒池執行緒數量超過corepoolsize時,多餘的空閒執行緒的存活時間。即,超過corepoolsize的空閒執行緒,在多長時間內,會被銷毀。

• unit: keepalivetime 的單位。

• workqueue:任務佇列,被提交但尚未被執行的任務。

• threadfactory:執行緒工廠,用於建立執行緒,一般用預設的即可。

• handler:拒絕策略。當任務太多來不及處理,如何拒絕任務。

接下來了解一下執行緒池的核心排程**(**結合圖去理解更好點)

簡單說就是當我們提交乙個任務時,會判斷執行緒執行數量是否小於corepoolsize,小於就直接分配執行緒執行該任務,大於就去執行佇列(workqueue),如果佇列有位置則進入佇列,如果失敗再次檢視執行緒池執行緒數量是否小於maximumpoolsize,小於則正價執行緒數數量執行該任務,如果達到maximumpoolsize則執行拒絕策略(handler)。

3.下面簡單介紹一下我們常見的佇列 模式

• 接提交的佇列:該功能由synchronousqueue物件提供。synchronousqueue是乙個特殊的blockingqueue。synchronousqueue沒有容量,每乙個插入操作都要等待乙個相應的刪除操作,反之,每乙個刪除操作都要等待對應的插入操作。如果使synchronousqueue,提交的任務不會被真實的儲存,而總是將新任務提交給執行緒執行,如果沒有空閒的程序,則嘗試建立新的程序.如果程序數里已經達到最大值.則執行拒絕策略。因此,使用synchronousqueue佇列.通常要設定很大的maximumpoolsize值,否則很容易執行拒絕策略。

•有界的任務佇列:有界的任務佇列可以使用arrayblockingqucue實現。arrdyblockingqueue的建構函式必須帶乙個容量引數.表示該佇列的最大容量,當使用有界的任務佇列時,若有新的任務需要執行.如果執行緒池的實際執行緒數小於corcpoolsize.則會優先建立新的執行緒,若大於fcorepoolsize,則會將新任務加入等持佇列。若等待佇列已滿,無法加入,則在匯流排程數不大於maximumpoolsize的前提下,建立新的程序執行任務,若大於maximumpooisizc,則執行櫃絕策略。可見,有界佇列僅當在任務佇列裝滿時.才可能將執行緒數提公升到corepoolsize以上,換言之.除非系統非常繁忙,否則確保核心執行緒數維持在corepooisize。

•無界的任務佇列:無界任務佇列可以通過 linkedblockingqueuc類實現。與有界佇列相比,除非系統資源耗盡,否則無界的任務佇列不存在任務入隊失敗的情況。當有新的任務到來,系統的執行緒數小 於corepoolsize時,執行緒池會生成新的執行緒執行任務,但當系統的執行緒數達到 corepoolsize後,就不會繼續增加。若後續仍有新的任務加入,而又沒有空閒的執行緒資源,則任務直接進入佇列等待。若任務建立和處理的速度差異很大,無界佇列會保持快速增長,直到耗盡系統記憶體。

•優先任務佇列:優先任務佇列是帶有執行優先順序的佇列。它通過priorityblockingqueue實現,可以控制任務的執行先後順序。它是乙個特殊的無界佇列。無論是有界佇列arrayblockingqueue,還是未指定大小的無界佇列linkedblockingqueue都是按照先進先出演算法處理任務的。而priorityblockingqueue則可以根據任務自身的優先順序順序先後執行,在確保系統效能的同時,也能有很好的質量保證(總是確保高優先順序的任務先執行)。

4.拒絕策略:

jdk內建的拒絕策略如下。

• abortpolicy策略:該策略會直接丟擲異常,阻止系統正常工作。

• callerrunspolicy策略:只要執行緒池未關閉,該策略直接在呼叫者執行緒中,執行當前被丟棄的任務。顯然這樣做不會真的丟棄任務,但是,任務提交執行緒的效能極有可能會急劇下降。

• discardoledestpolicy策略:該策略將丟棄最老的乙個請求,也就是即將被執行的乙個任務,並嘗試再次提交當前任務。

• discardpolicy策略:該策略默默地丟棄無法處理的任務,不予任何處理。如果允許任務丟失,我覺得這可能是最好的一種方案了吧。

以上內建的策略均實現了rejectedexecutionhandler介面,若以上策略仍無法滿足實際應用需要,完全可以自己擴充套件 rejectedexecutionhandler 介面。

理解執行緒池

建立執行緒池的一種方式 threadpoolexecutor threadpoolexecutor new threadpoolexecutor corepoolsize,maximumpoolsize,keepalivetime,unit,workqueue,threadfactory,handl...

理解執行緒池

為什麼要使用執行緒池?我們使用乙個執行緒的步驟 1.建立執行緒 2.使用執行緒 3.銷毀執行緒 每使用乙個執行緒必須經過這三個步驟,如果步驟1,和步驟3所需要的時間和大於步驟2,我們就得思考,會不會本末倒置,怎麼樣提高效能?縮短建立和銷毀執行緒的時間!當乙個執行緒完成自己的工作後,不去銷毀它,讓它繼...

執行緒池的理解

原來一直對執行緒池心存疑惑.第乙個疑惑是.執行緒類在例項化的時候就已經指定了run函式了,也就是說,乙個執行緒在例項化的時候,他能做什麼就已經定下來了,要做別的事,就要新開乙個執行緒.這感覺就和執行緒池的思想違背了,怎麼樣從執行緒池裡面拿乙個執行緒出來就可以執行呢?執行完了然後再放回去呢?第二個疑惑...