java執行緒池原理講解及常用建立方式

2021-08-07 16:14:10 字數 4229 閱讀 9801

首先我們先看一下執行緒池的類圖關係,只有理解了這些類的關係後,後面的理解就容易多了:

下面舉乙個例項來看看具體的使用個,這裡以newfixedthreadpool()為例:

public class threadpooldemo catch(interruptedexception e)

} } public static void main(string args)

}}

上述**中,我們建立了固定大小的執行緒池,內有5個執行緒。然後我們依次向執行緒池提交了10個任務。此後,執行緒池就會安排排程這10個任務。每個任務都會講自己的執行時間和執行這個執行緒的id列印出來,並且在這裡,安排每個任務執行1秒鐘。得到的結果下:

1504283763066:thread id:10

1504283763066:thread id:9

1504283763066:thread id:12

1504283763067:thread id:13

1504283763067:thread id:11

1504283764066:thread id:9

1504283764066:thread id:10

1504283764066:thread id:12

1504283764067:thread id:11

1504283764067:thread id:13

首先我們先看newfixedthreadpool()和newcachedthreadpool()的內部實現,之所以選它們,因為它們具有代表性。

public static executorservice newfixedthreadpool(int nthreads) 

public static executorservice newcachedthreadpool()

由以上執行緒池的實現**可以看到,它們都只是threadpoolexecutor類的封裝。接下來看看threadpoolexecutor最重要的構造數:

public threadpoolexecutor(int corepoolsize,

int maximumpoolsize,

long keepalivetime,

timeunit unit,

blockingqueueworkqueue)

函式的引數含義如下:

workqueue引數

引數workqueue指被提交但未執行的任務佇列,它是乙個blockingqueue介面的物件,僅用來存放runnable物件。接下來介紹幾個主要的任務佇列,它們都是實現了blockingqueue

(1)直接提交的佇列:該功能有synchronousqueue物件提供。synchronousqueue是乙個特殊的blockingqueue。synchronousqueue沒喲容量,每乙個插入操作都要等待乙個相應的刪除操作,反之,也是一樣。如果我們使用synchronousqueue,提交的任務不會儲存在synchronousqueue中(這裡synchronousqueue的內部實現大家可以查閱一下資料,這裡不詳細說了),而總是將新任務提交給執行緒執行,如果沒有空閒的程序,則嘗試建立新的程序,如果程序數量已經達到最大值,執行拒絕策略。因此,使用synchronousqueue佇列,通常設定很大的maximumpoolsize值,否則很容易執行拒絕策略。

(2)有界的任務佇列:有界的任務佇列可以使用arrayblockingqueue實現。因為它是基於陣列實現的,這樣我們初始化乙個固定容量即可。當時用有界的任務佇列時。若有新的任務需要執行,如果執行緒池的實際執行緒數小於corepoolsize,則會優先建立新的執行緒,若大於corepoolsize,則會將新任務加入等待佇列。若等待佇列已滿,無法加入,則在匯流排程數不大於maximumpoolsize的前提下,建立新的程序執行任務。若大於maximumpoolsize,則執行拒絕策略。

(3)無界任務佇列:無界任務佇列可以通過linkedblockingqueue類實現。與有界佇列相比,除非系統資源耗盡,否則無界的任務佇列不存在任務入隊失敗的情況。當新任務到來,系統的執行緒數小於corepoolsize時,執行緒池會生成新的執行緒執行任務,但當系統的執行緒數達到corepoolsize後,就不會繼續增加。若後續仍有新的任務加入,而沒有空閒的執行緒資源,則任務直接進入佇列等待。

說完workqueue引數再來看看newfixedthreadpool()和newcachedthreadpool()兩個方法的內部實現,第乙個方法返回乙個corepoolsize和maximumpoolsize大小一樣的,並且使用了linkedblockingqueue任務佇列的執行緒池。第二個方法返回corepoolsize為0,maximumpoolsize無窮大的執行緒池,該執行緒池內無線程,而當任務被提交時,該執行緒池會使用空閒的執行緒執行任務,若無空閒執行緒,則將任務加入synchronousqueue佇列,而synchronousqueue佇列是一種直接提交的佇列,它總會迫使執行緒池增加新的執行緒執行任務。對於newcachedthreadpool(),如果同時有大量任務被提交,而任務的執行又不那麼快,那麼系統便會開啟大量的執行緒處理,這樣做很快會耗盡系統資源。

threadpoolexecutor執行緒池的核心排程**:

public void execute(runnable command) 

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

else if (!addworker(command, false))

reject(command);

}

當我們使用執行緒池執行任務時,即使用execute()方法呼叫任務時,threadpoolexecutor的排程源**如上面所示,**第5行的workercountof()函式取得當前執行緒的執行緒總數。當執行緒總數小於corepoolsize核心執行緒數是,會將任務通過addworker()方法直接排程執行。否則,則在第10行**workqueue.offer()進入等列。如果進入等待失敗,則會執行第17行,將任務直接提交給執行緒池。如果當前執行緒數已經達到maximumpoolsize,則提交失敗,執行最後一行**。

邏輯圖如下:

handler引數

threadpoolexecutor的這個引數制定了拒絕策略。也就是當任務數量超過系統實際承載能力時,threadpoolexecutor需要執行的拒絕策略。jdk預設有自己的預設拒絕策略。接下來我們實現rejectedexecutionhandler自定義乙個自己的拒絕策略:

public class threadpooldemo catch(interruptedexception e)

} } public static void main(string args) throws interruptedexception

});for(int i =0;i

1504289276848:thread id:9

1504289276858:thread id:10

demo.threadpooldemo$mytask@28d76d1eis discard

demo.threadpooldemo$mytask@28d76d1eis discard

1504289276889:thread id:11

1504289276892:thread id:13

Java執行緒池實現原理

threadpoolexecutor是jdk提供的執行緒池實現,threadpoolexector實現了execturo介面,可以自動幫助使用者建立,銷毀和保護執行緒,先來看一下最基本的使用方式 建立乙個執行緒池final executor executor new threadpoolexecut...

java 執行緒池的原理

頻繁地建立執行緒很浪費資源。執行緒池的執行緒可以復用,執行完乙個任務後可以執行另乙個任務。runstate表示當前執行緒池的狀態,它是乙個volatile變數用來保證執行緒之間的可見性 下面的幾個static final變數表示runstate可能的幾個取值。當建立執行緒池後,初始時,執行緒池處於r...

java執行緒池的原理

前天去面試,一問三不知,然後回來趕緊惡補下,發現執行緒池沒有想象中那麼難,今天通過閱讀優秀的部落格對執行緒池大概坐下總結。大神部落格 頂層 介面executor,預設只有乙個executor方法,void 第二層介面 executorservice繼承executor介面,定義一些執行執行緒池的方法...