jdk1.5為我們新增了兩種實現多執行緒的方式:執行緒池和callable介面,本次我們來玩一下執行緒池。
首先,介紹一下threadpoolexecutor的建構函式及其7個引數的內容:
其次,我們來看一下執行緒池執行任務的流程:
threadpoolexecutor原始碼對execute方法的說明:
其本質就是threadpool執行緒池的執行任務流程,用流程圖標意如下:
在單輪次的多個任務過來時,執行緒池中的執行緒執行任務時完全符合上述規律。
下面我寫了**進行測試,我把核心執行緒數設定為2個,最大可擴充套件執行緒數設定為4個,非核心執行緒數空閒生存時間設定為2s,阻塞佇列設定為3個。
public
class
threadpooldemo);
} timeunit.milliseconds.
sleep
(500);
system.out.
println
("***************==第二輪執行緒***************===");
for(
int i =
0; i <
4; i++))
;}}catch
(interruptedexception e)
finally
}}
測試結果如下:
按照常理來想,那麼第一輪結束後有4個執行緒已經空閒下來了,那麼第二輪任務過來時應該是這些空閒下來的任務直接接收任務,然後執行任務吧。但是測試結果呈現的顯然不是我們預想的。
為了弄清楚其底層的原理,我們先來剖析一下,在第二輪任務來臨時,執行緒池現有4個執行緒處於活躍狀態,阻塞佇列容量為3,現在處於空的狀態。
第二輪有4個任務,但是執行緒只執行了3個任務,有1任務執行了拒絕策略。
明明執行緒池中現在有4個執行緒是處於活躍狀態的,為什麼不將4個任務全部執行,反而要將其中1個任務拒絕呢?
那麼,我又進行了第二次測試。
這次測試,我讓非核心執行緒在空閒2秒後失效(其他**不變),那麼,執行緒池在即將執行第二輪任務時,執行緒池中只剩下核心執行緒(2個),並且阻塞佇列(容量為3)也是空的。
將上述測試**中的
timeunit.milliseconds.
sleep
(500
);
修改為:
timeunit.milliseconds.
sleep
(2500
);
然後執行,測試的結果如下:
本次測試,在第二輪任務來臨時,執行緒池現有2個執行緒處於活躍狀態,阻塞佇列容量為3,而且處於空閒狀態。
這次卻將4個任務全部執行了。
仔細檢視原始碼及其文件說明後,也沒有發現問題。
經過仔細思考,發現執行緒池的執行流程官方文件所寫的是正確的(執行緒池的執行任務流程示意圖表示的流程也是正確的)。因為當多個任務來臨時,執行緒池不是首先判斷是否有空閒的執行緒(execute方法根本就沒有這個流程,這樣的設計完全不符合人的思維習慣),而是直接判定執行緒數是否達到核心執行緒數,如果已達到,則進入阻塞佇列,如果阻塞佇列已滿,再進行判定執行緒數是否已達到最大可擴充套件執行緒數,如果已達到則執行拒絕策略。
詳細分析如下:
在測試1中即將執行第二輪任務時的執行緒池的狀態如下:
執行緒池現有4個執行緒處於活躍狀態,阻塞佇列容量為3,現在處於空的狀態。
當第二輪任務過來後,
1.判定現有執行緒數(目前是4)是否達到核心執行緒數(2),結果是已達到,進行下一步判定;
2.判定阻塞佇列是否已滿,目前任務是4個,阻塞佇列的容量是3個,所以其中有3個任務放入了阻塞佇列,另外1個任務需要進行下一步的判定;
3.判定現有執行緒數(目前是4)是否已達到最大可擴充套件執行緒數(4),結果是已達到,那麼最後1個任務被執行拒絕策略。
在測試2即將執行第二輪任務時執行緒池的狀態如下:
執行緒池現有2個執行緒處於活躍狀態,阻塞佇列容量為3,現在處於空的狀態。
當第二輪任務過來後,
1.判定現有執行緒數(目前是2)是否達到核心執行緒數(2),結果是已達到,進行下一步判定;
2.判定阻塞佇列是否已滿,目前任務是4個,阻塞佇列的容量是3個,所以其中有3個任務放入了阻塞佇列,另外1個任務需要進行下一步的判定;
3.判定現有執行緒數(目前是2)是否已達到最大可擴充套件執行緒數(4),結果是未達到,那麼執行緒池建立新的執行緒,並執行這最後1個任務。
執行緒池的工作流程如下:
1.判定現有執行緒數是否達到核心執行緒數,如果未達到,則建立執行緒並執行任務;
2.如果現有執行緒數已達到核心執行緒數,則判定阻塞佇列是否已滿,未滿則進入阻塞佇列;
3.如果阻塞佇列已滿,則判定現有執行緒數是否已達到最大可擴充套件執行緒數,如果未達到,則建立執行緒並執行任務;
4.如果現有執行緒數已達到最大可擴充套件執行緒數則執行拒絕策略。
官方文件的說明的和原始碼寫的是一致的,經測試也沒有問題,只是執行緒池的這種工作流程不符合人類的思維習慣。
有不可思議的目標 就有不可思議的結果
3月3號 開學 可惜學校的效率不好 要隔上5天才上課 悲劇 最後的半年了 換了新的老師 看上去很有個人魅力 蠻好 尊敬的老師還只有屈指可數的那幾個 失敗。或許是我沒有好好學習,沒有發現 陳昌主 現在的老師絕對算的上乙個,親和力很好,而且很勤奮。寫下這4個月的目標 1 english can read...
不可思議的BUG
莫看江面平如鏡,要看水底萬丈深 記一次由表象引起的不是bug的bug 先上圖 上圖,第一行是實際請求報錯的介面,第二行才是列印出的真正配置的介面位址,由於專案上會根據專案環境,會切換介面位址,方便開發 測試 生產。我的第一反應就是切換位址的邏輯有問題。仔細跟了他寫的 確實在介面請求前,位址是開發位址...
不可思議的縮小vetor
如果vector的空間不夠時,會自動的申請新的空間,空間大小為舊空間的2倍,然後將舊空間的資料拷貝到新空間,最後將舊空間釋放。這種保留額外的記憶體空間已被將來增長的需要,從而防止增加新元素時過於頻繁的重新分配。這也是vector比陣列好的一點。當然有沒有想過,1 如果原有的舊空間為128,現在需要的...