08 執行緒池

2021-10-22 07:24:57 字數 3446 閱讀 2127

降低系統資源消耗,通過重用已存在的執行緒,降低執行緒建立和銷毀造成的消耗;

提高系統響應速度,當有任務到達時,通過復用已存在的執行緒,無需等待新執行緒的建立便能立即執行;

方便執行緒併發數的管控。因為執行緒若是無限制的建立,可能會導致記憶體占用過多而產生oom,並且會造成cpu過度切換(cpu切換執行緒是有時間成本的(需要保持當前執行執行緒的現場,並恢復要執行執行緒的現場))。

延時定時執行緒池,可以支援定時任務。

執行緒池流程

判斷核心執行緒池是否已滿,沒滿則建立乙個新的工作執行緒來執行任務。已滿則。

判斷任務佇列是否已滿,沒滿則將新提交的任務新增在工作佇列,已滿則。

判斷整個執行緒池是否已滿,沒滿則建立乙個新的工作執行緒來執行任務,已滿則執行飽和策略。

//構造方法

public

threadpoolexecutor

(int corepoolsize,

int maximumpoolsize,

long

keepalivetime, timeunit unit, blockingqueue

workqueue)

//呼叫

threadpoolexecutor tpe =

newthreadpoolexecutor(2

,4,60

, timeunit.seconds,

newarrayblockingqueue

(4),

executors.

defaultthreadfactory()

,new

threadpoolexecutor.callerrunspolicy()

);

corepoolsize(執行緒池核心執行緒數):當向執行緒池提交乙個任務時,若執行緒池已建立的執行緒數小於corepoolsize,即便此時存在空閒執行緒,也會通過建立乙個新執行緒來執行該任務,直到已建立的執行緒數大於或等於corepoolsize時,(除了利用提交新任務來建立和啟動執行緒(按需構造),也可以通過prestartcorethread() 或 prestartallcorethreads() 方法來提前啟動執行緒池中的基本執行緒。)

maximumpoolsize(執行緒池最大執行緒數):執行緒池所允許的最大執行緒個數。當佇列滿了,且已建立的執行緒數小於maximumpoolsize,則執行緒池會建立新的執行緒來執行任務。另外,對於無界佇列,可忽略該引數。

keepalivetime(執行緒存活保持時間)當執行緒池中線程數大於核心執行緒數時,執行緒的空閒時間如果超過執行緒存活時間,那麼這個執行緒就會被銷毀,直到執行緒池中的執行緒數小於等於核心執行緒數。

workqueue(任務佇列):用於傳輸和儲存等待執行任務的阻塞佇列。

threadfactory(執行緒工廠):用於建立新執行緒。threadfactory建立的執行緒也是採用newthread()方式,threadfactory建立的執行緒名都具有統一的風格:pool-m-thread-n(m為執行緒池的編號,n為執行緒池內的執行緒編號)。

handler(執行緒飽和策略):當執行緒池和佇列都滿了,再加入執行緒會執行此策略。

阻塞佇列:當佇列中元素個數為0時,get()方法阻塞。當佇列已滿時add()方法阻塞。

阻塞佇列可以保證任務佇列中沒有任務時阻塞獲取任務的執行緒,使得執行緒進入wait狀態,釋放cpu資源。當佇列中有任務時才喚醒對應執行緒從佇列中取出訊息進行執行。使得執行緒不會一直占用cpu資源。

盡量使用較小的執行緒池,一般為cpu核心數+1。 因為cpu密集型任務使得cpu使用率很高,若開過多的執行緒數,會造成cpu過度切換。

io密集型任務

可以使用稍大的執行緒池,一般為2*cpu核心數。 io密集型任務cpu使用率並不高,因此可以讓cpu在等待io的時候有其他執行緒去處理別的任務,充分利用cpu時間。

混合型任務

可以將任務分成io密集型和cpu密集型任務,然後分別用不同的執行緒池去處理。 只要分完之後兩個任務的執行時間相差不大,那麼就會比序列執行效率更高。

因為如果劃分之後兩個任務執行時間有資料級的差距,那麼拆分沒有意義。

因為先執行完的任務就要等後執行完的任務,最終的時間仍然取決於後執行完的任務,而且還要加上任務拆分與合併的開銷,得不償失。

blockingqueue知識點可參考blockingqueue的原理及使用方法

常用的幾種blockingqueue:

arrayblockingqueue(int i):

規定大小的blockingqueue,其構造必須指定大小。其所含的物件是fifo順序排序的。

linkedblockingqueue():

或者(int i):大小不固定的blockingqueue,若其構造時指定大小,生成的blockingqueue有大小限制,不指定大小,其大小有integer.max_value來決定。其所含的物件是fifo順序排序的。如果offer()的速度大於pull()的速度,有可能造成記憶體溢位

priorityblockingqueue()或者(int i):

類似於linkedblockingqueue,但是其所含物件的排序不是fifo,而是依據物件的自然順序或者建構函式的comparator決定。

synchronizedqueue():

特殊的blockingqueue,對其的操作必須是放和取交替完成。

cachedthreadpool:

該執行緒池中沒有核心執行緒,非核心執行緒的數量為integer.max_value,就是無限大,當有需要時建立執行緒來執行任務,沒有需要時**執行緒,適用於耗時少,任務量大的情況。使用不當會造成cpu爆滿

secudlethreadpool:

週期性執行任務的執行緒池,按照某種特定的計畫執行執行緒中的任務,有核心執行緒,但也有非核心執行緒,非核心執行緒的大小也為無限大。適用於執行週期性的任務。

singlethreadpool:

只有一條執行緒來執行任務,適用於有順序的任務的應用場景。

fixedthreadpool:

定長的執行緒池,有核心執行緒,核心執行緒的即為最大的執行緒數量,沒有非核心執行緒。使用不當會造成記憶體溢位

execute() 引數 runnable ;submit() 引數 (runnable) 或 (runnable 和 結果 t) 或

(callable)

execute()方法用於提交不需要返回值的任務,所以無法判斷任務是否被執行緒池執行成功與否;

submit()方法用於提交需要返回值的任務。執行緒池會返回乙個 future 型別的物件,通過這個 future

物件可以判斷任務是否執行成功,並且可以通過 future 的get()方法來獲取返回值,get()方法會阻塞當前執行緒直到任務完成,而使用 get(long timeout,timeunit unit)方法則會阻塞當前執行緒一段時間後立即返回,這時候有可能任務沒有執行完。

08 執行緒池

執行緒池的作用是什麼 如果沒有執行緒池,使用者的每乙個請求都會經歷申請資源建立執行緒,執行執行緒,釋放資源銷毀執行緒這個過程,很多時間浪費在建立和銷毀這兩件事情上。如果使用者請求時執行緒已經存在,使用者使用執行緒結束也不用去考慮如何銷毀,由於減少了每個任務呼叫的開銷,它們通常可以在執行大量非同步任務...

執行緒 執行緒池

執行緒池是一種多執行緒處理形式,處理過程中將任務新增到佇列,然後在建立執行緒後執行,主要實現 建立執行緒和管理執行緒,並且給執行緒分配任務。執行緒池中的執行緒是併發執行的。乙個比較簡單的執行緒池至少應包含執行緒池管理器 工作執行緒 任務列隊 任務介面等部分。其中執行緒池管理器的作用是建立 銷毀並管理...

執行緒 執行緒池

乙個簡單執行緒的建立和銷毀如下 與程序程序相比,執行緒是一種輕量級的工具,但是輕量並不代表沒有,它的建立和關閉依然需要花費時間,如果建立和銷毀的時間還大於執行緒本身完成的工作,那就會得不償失,甚至會造成out of memory。即使沒有,大量的執行緒 也會給gc帶來巨大的壓力。為了解決這樣的問題,...