Java執行緒池

2021-08-04 22:29:24 字數 4551 閱讀 3093

多執行緒的軟體設計方法確實可以最大限度地發揮現代多核處理器的計算能力,提高生產系統的吞吐量和效能。但是,若不加控制和管理的隨意使用執行緒,對系統的效能反而會產生不利的影響。

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

執行緒池也是類似的概念。執行緒池中,總有幾個活躍的執行緒。當你需要使用執行緒時,可以從池子中隨便拿乙個空閒執行緒,當完成工作時,並不急關閉執行緒,而是將這個執行緒退回到池子,方便其他人使用。也就是說,建立執行緒變成了從執行緒池獲得空閒執行緒,關閉執行緒變成了向池子歸還執行緒。

呼叫executors的相關靜態方法(下邊介紹)建立執行緒池後,就可以呼叫threadpoolexecutor類的execute(task)(task是runnable型別的任務)方法執行給定的runnable任務task了。接下來先看下executors的幾個常用的建立執行緒池的靜態方法。

該靜態方法返回乙個固定執行緒數量的執行緒池。該執行緒池中的執行緒數量始終不變。有新任務提交時,執行緒池中有空閒執行緒,則立即執行;若沒有,則新任務被暫存在乙個任務佇列中,直到有空閒執行緒。若在關閉前的執行期間由於失敗而導致任何執行緒終止,那麼乙個新執行緒將代替它執行後續的任務(若需要)。

public

static executorservice newfixedthreadpool(int nthreads)

可以看到該方法呼叫threadpoolexecutor方法的引數情況,corepool和maximumpoolsize是相同的,也就是該執行緒池中線程數達到這個數目後就不會再繼續建立新的執行緒,而是新增到linkedblockingqueue()佇列中,該佇列是按fifo先進先出排序元素,在此處的容量為integer.max_value(此容量的佇列有時也稱為無界佇列)。

返回只有乙個worker執行緒的執行緒池。以無界佇列linkedblockingqueue方式執行該執行緒。如果因為在關閉前的執行期間出現失敗而終止了此單個執行緒,若需要,乙個新縣城將代替它執行後續的任務。多餘任務儲存在任務佇列,先入先出順序執行。

public

static executorservice newsinglethreadexecutor()

返回乙個可根據實際情況調整執行緒數量的執行緒池。執行緒池的執行緒數量不確定,但若有空閒執行緒可以復用,則會優先使用可復用的執行緒。若所有執行緒均在工作,又有新任務提交,則會建立新的執行緒處理任務。所有執行緒在當前任務執行完畢後,將返回執行緒池進行復用。

public

static executorservice newcachedthreadpool()

由定義可看出,該執行緒池最大執行緒數量為integer.max_value,若執行緒空閒60s未被使用則被終止,呼叫synchronousqueue作為任務佇列,該佇列是乙個沒有資料緩衝的blockingqueue,每個插入操作必須等待另乙個執行緒的對應移除操作,否則將被掛起。

返回scheduledexecutorservice物件,但該方法建立乙個指定執行緒數量的執行緒池,可安排在給定延遲後執行命令或頂起地執行。

public

static scheduledexecutorservice newscheduledthreadpool(int corepoolsize)

public

scheduledthreadpoolexecutor(int corepoolsize)

scheduledthreadpoolexecutor繼承了threadpoolexecutor類,使用super呼叫其父類的構造方法,實現執行緒池的建立。

executors類則扮演者執行緒池工廠的角色,通過executors的靜態方法可以取得乙個擁有特定功能的執行緒池。上一步介紹的幾個核心執行緒池,雖看起來建立的執行緒有著完全不同的功能特點,但其內部實現均使用了threadpoolexecutor實現,都是threadpoolexecutor類的封裝,該類的構造方法如下:

public

threadpoolexecutor(int corepoolsize,

int maximumpoolsize,

long keepalivetime,

timeunit unit,

blockingqueueworkqueue,

threadfactory threadfactory,

rejectedexecutionhandler handler)

可以通過給定初始化引數建立乙個新的threadpoolexecutor,對於幾個引數的含義如下介紹:

workqueue是乙個blockingqueue介面的物件,僅用於存放runnable物件。根據佇列功能分類,在threadpoolexecutor的建構函式中可使用以下幾種blockingqueue:

當把乙個runnable交給執行緒池去執行的時候,其處理流程大概如下:

threadpoolexecutor執行緒池的核心排程**是execute函式,該段**充分體現了執行緒池的工作邏輯:

public

void

execute(runnable command)

if(isrunning(c) && workqueue.offer(command))

else

if (!addworker(command, false)) //17行

reject(command);

}

**第五行的workercountof()函式取得了當前執行緒池的執行緒總數。當執行緒總數小於corepoolsize核心執行緒數時,會將任務通過addworker()方法直接排程執行。否則,則在第十行**處(workqueue.offer())進入等待佇列。如果進入等待佇列失敗(比如有界佇列到達了上限或者使用了synchronousqueue),則會執行第17行,將任務直接提交給執行緒池。如果當前執行緒數已經達到了maximumpoolsize,則提交失敗,就執行18行的拒絕策略。

threadpoolexecutor的任務排程邏輯:

拒絕策略可以說是系統超負荷執行時的補救措施,通常由於壓力太大而引起的,也就是執行緒池中的執行緒用完了,無法繼續為新任務服務,同時,等待佇列中也已經排滿了,再也塞不下新任務了。這時就需要一套機制合理的處理這個問題。

jdk內建提供了四種拒絕策略:

執行緒池通過threadfactory介面來建立執行緒,其只有乙個方法:

thread newthread(runnable r);

threadpoolexecutor類中若沒有指定執行緒工程threadfactory,就會呼叫預設的工廠defaultthreadfactory,該靜態方法中封裝了defaultthreadfactory類,其實現了threadfactory介面及newthread方法,其實現如下:

static

class

defaultthreadfactory

implements

threadfactory

public thread newthread(runnable r)

}

很明顯,newthread方法就是該工廠類的工廠方法,也就是其核心實現。

若想要對執行緒池做一些擴充套件,比如,監控每個任務執行的開始和結束時間,或者其他一些自定義的增強功能,如何去做?

其實,threadpoolexecutor是乙個可擴充套件的執行緒池。它提供了beforeexecute()、afterexecute()和terminated()三個介面對執行緒池進行控制。

如下使用:

boolean ran = false;

beforeexecute(thread, task); //執行前

try catch (runtimeexecption ex)

預設的threadpoolexecutor實現中,提供了空的beforeexecute()和afterexecute()實現。實際應用中,可以對其進行擴充套件來實現對執行緒池執行狀態的跟蹤,輸出一些有用的除錯資訊,以幫助系統故障診斷,這對於多執行緒程式錯誤排查是很有幫助的。

在提交任務時若直接使用submit方法,會導致沒有異常堆疊提示資訊(如除法運算,除數為0)。可以改用execute()方法如下:

pools.execute(new task());

或者改造submit():

future re = pools.submit(new task());

re.get();

Java執行緒池

executors類詳解 此包中所定義的 executor executorservice scheduledexecutorservice threadfactory 和 callable 類的工廠和實用方法。此類支援以下各種方法 建立並返回設定有常用配置字串的 executorservice 的...

Java執行緒池

一 執行緒池 單執行緒 public static void runsinglethreadpool public static void runsinglethreadpoolwithfactory private static class mythreadfactory implements t...

java 執行緒池

1.執行緒池的作用 限制系統中執行執行緒的數量 2.為什麼要用執行緒池 2.1.減少了建立和銷毀執行緒的次數,每個工作執行緒都可以被重複利用,可執行多個任務.2.2 可以根據系統的承受能力,調整執行緒池中工作線執行緒的數目,防止因為消耗過多的記憶體,而把伺服器累趴下。3.執行緒池介面類 3.1 ex...