併發程式設計的藝術 執行緒池原始碼解析

2021-09-24 07:53:55 字數 2576 閱讀 5575

執行緒池的作用:

1,降低資源消耗。通過重複利用已建立的執行緒降低執行緒建立和銷毀造成的消耗。

2,提搞響應速度。當任務到達時,任務可以不需要等到執行緒建立就能立即執行。

3,提高系統的客觀理性。執行緒是稀缺資源,如果無限制地建立,不僅會消耗系統資源,還會降低系統的穩定性,使用執行緒池可以進行統一分配,調優和監控。但是,要做到合理利用執行緒池,必須對其實現原理瞭如指掌。

一,執行緒池的實現原理

當想乙個執行緒池提交乙個新任務時,執行緒池的處理流程如下:

1,執行緒池判斷核心執行緒池裡面的執行緒是否都在執行任務,如果核心執行緒未滿,則建立乙個新的工作執行緒來執行任務。如果核心執行緒已滿,則進如下乙個流程判斷。

2,執行緒池判斷工作佇列是否已經滿了,如果工作佇列沒有滿,則將新提交的任務儲存在這個工作佇列裡。如果工作佇列已經滿了,則進入下個流程。

3,執行緒池判斷執行緒池的執行緒是否都處於工作狀態,如果沒有,則建立乙個新的工作執行緒來執行任務。如果已經滿了,則提交給飽和策略來處理這個任務。

threadpoolexecutor執行execute方法,有如下四種情況:

1,如果當前執行的執行緒少於corepoolsize,則建立新執行緒來執行任務(需要獲取全域性鎖)。

2,如果執行的執行緒等於或者多餘corepoolsize,則將任務加入blockingqueue。

3,如果無法將任務加入blockingqueue,則建立新的執行緒來處理任務(需要獲取全域性鎖)。

4,如果建立新執行緒將使當前執行的執行緒超出maximumpoolsize,任務將被拒絕,並呼叫rejectexecutionhandler.rejectedexecution方法。

threadpoolexecutor採取上述步驟的總體設計思路,是為了執行execute方法時候,盡可能避免獲取全域性鎖。在threadpoolexecutor完成預熱之後(即當前執行的執行緒數目大於等於核心執行緒數目),幾乎所有的execute方法呼叫的都是執行步驟2,而步驟2是不需要獲取全域性鎖的,保證了效能。

threadpoolexecutor的使用

執行緒池的建立

​ 我們要用執行緒池來統一分配和管理我們的執行緒,那首先我們要建立乙個執行緒池出來,還是有很多大牛已經幫我們寫好了很多方面的**的,executors的工廠方法就給我們提供了建立多種不同執行緒池的方法。因為這個類只是乙個建立物件的工廠,並沒有涉及到很多的具體實現,所以我不會過於詳細地去說明。

​ 老規矩,還是直接上**吧。

publicstaticexecutorservicenewfixedthreadpool(intnthreads)

這裡也就舉出乙個方法的例子來進行之後的講解吧,我們可以看出,executors只是個工廠而已,方法也只是來例項化不同的物件,實際上例項化出來的關鍵類就是threadpoolexecutor。現在我們就先來簡單地對threadpoolexecutor建構函式內的每個引數進行解釋一下吧。

corepoolsize(核心執行緒池大小):當提交乙個任務到執行緒池時,執行緒池會建立乙個執行緒來執行任務,即使其他空閒的基本執行緒能夠執行新任務也會建立執行緒,當任務數大於核心執行緒數的時候就不會再建立。在這裡要注意一點,執行緒池剛建立的時候,其中並沒有建立任何執行緒,而是等任務來才去建立執行緒,除非呼叫了prestartallcorethreads()或者prestartcorethread()方法 ,這樣才會預先建立好corepoolsize個執行緒或者乙個執行緒。

maximumpoolsize(執行緒池最大執行緒數):執行緒池允許建立的最大執行緒數,如果佇列滿了,並且已建立的執行緒數小於最大執行緒數,則執行緒池會再建立新的執行緒執行任務。值得注意的是,如果使用了無界佇列,此引數就沒有意義了。

unit(keelalivetime的時間單位):keelalivetime的時間單位,一共有7種,在這裡就不列舉了。

workqueue(阻塞佇列):阻塞佇列,用來儲存等待執行的任務,這個引數也是非常重要的,在這裡簡單介紹一下幾個阻塞佇列。

arrayblockingqueue:這是乙個基於陣列結構的有界阻塞佇列,此佇列按照fifo的原則對元素進行排序。

linkedblockingqueue:乙個基於鍊錶結構的阻塞佇列,此佇列按照fifo排序元素,吞吐量通常要高於arrayblockingqueue。靜態工廠方法executors.newfixedthreadpool()就是使用了這個佇列。

synchronousqueue:乙個不儲存元素的阻塞佇列。每個插入操作必須等到另乙個執行緒呼叫移除操作,否則插入操作一直處於阻塞狀態。吞吐量通常要高於linkedblockingqueue,靜態工廠方法executors.newcachedthreadpool()就使用了這個佇列。

priorityblockingqueue:乙個具有優先順序的無阻塞佇列。

handler(飽和策略);當執行緒池和佇列都滿了,說明執行緒池已經處於飽和狀態了,那麼必須採取一種策略來處理還在提交過來的新任務。這個飽和策略預設情況下是abortpolicy,表示無法處理新任務時丟擲異常。共有四種飽和策略提供,當然我們也可以選擇自己實現飽和策略。

abortpolicy:直接丟棄並且丟擲rejectedexecutionexception異常

discardoldestpolicy:丟棄佇列裡最近的乙個任務,並執行當前任務。

discardpolicy:丟棄任務並且不丟擲異常。

如何一起學習,有沒有免費資料?

併發程式設計的藝術 執行緒池原始碼解析

執行緒池的作用 1,降低資源消耗。通過重複利用已建立的執行緒降低執行緒建立和銷毀造成的消耗。2,提搞響應速度。當任務到達時,任務可以不需要等到執行緒建立就能立即執行。3,提高系統的客觀理性。執行緒是稀缺資源,如果無限制地建立,不僅會消耗系統資源,還會降低系統的穩定性,使用執行緒池可以進行統一分配,調...

mysql 執行緒池原始碼 執行緒池原始碼解析

1.前言 我個人覺得理論性的東西可能大家都懂,但是具體的實現細節可能並不是很清楚所以才想記錄一下,加深記憶。2.關鍵原始碼解析 1 ctl private final atomicinteger ctl new atomicinteger ctlof running,0 private static...

原始碼解析執行緒池的執行流程

任務被提交到執行緒池,會先判斷當前執行緒數量是否小於corepoolsize,如果小於則建立執行緒來執行提交的任務,否則將任務放入workqueue佇列,如果workqueue滿了,則判斷當前執行緒數量是否小於maximumpoolsize,如果小於則建立執行緒執行任務,否則就會呼叫handler拒...