一.什麼是線程池?
線程池就是以一個或多個線程[迴圈執行]多個應用邏輯的線程集合.
注意這裡用了線程集合的概念是我生造的,目的是為了區分執行一批應用邏輯的多個線程和
線程組的區別.關於線程組的概念請參閱基礎部分.
一般而言,線程池有以下幾個部分:
1.完成主要任務的一個或多個線程.
2.用於調度管理的管理線程.
3.要求執行的任務隊列.
那麼如果一個線程迴圈執行一段代碼是否是線程池?
如果極端而言,應該算,但實際上迴圈代碼應該算上一個邏輯單元.我們說最最弱化的線程池
應該是迴圈執行多個邏輯單元.也就是有一批要執行的任務,這些任務被獨立為多個不同的執行
單元.比如:
int x = 0;
while(true){
x ++;
}
這就不能說迴圈中執行多個邏輯單元,因為它只是簡單地對迴圈外部的初始變數執行++操作.
而如果已經有一個隊列
ArrayList al = new ArrayList();
for(int i=0;i<10000;i++){
al.add(new AClass());
}
然後在一個線程中執行:
while(al.size() != 0){
AClass a = (AClass)al.remove(0);
a.businessMethod();
}
我們說這個線程就是迴圈執行多個邏輯單元.可以說這個線程是弱化的線程池.我們習慣上把這些
相對獨立的邏輯單元稱為任務.
二.為什麼要建立線程池?
線程池屬於對象池.所有對象池都具有一個非常重要的共性,就是為了最大程度複用對象.那麼
線程池的最重要的特徵也就是最大程度利用線程.
從編程模型模型上說講,在處理多任務時,每個任務一個線程是非常好的模型.如果確實可以這麼
做我們將可以使用編程模型更清楚,更最佳化.但是在實際應用中,每個任務一個線程會使用系統限
入"過度切換"和"過度開銷"的泥潭.
打個比方,如果可能,生活中每個人一輛房車,上面有休息,娛樂,餐飲等生活措施.而且道路交道永遠
不堵車,那是多麼美好的夢中王國啊.可是殘酷的現實告訴我們,那是不可能的.不僅每個人一輛車
需要無數多的社會資源,而且地球上所能容納的車輛總數是有限制的.
首先,建立線程本身需要額外(相對於執行任務而必須的資源)的開銷.
作業系統在每建立一個線程時,至少需要建立以下資源:
線程核心對象用於對線程內容相關的管理.
使用者模式執行棧.
核心模式執行棧.
這些資源被線程佔有後作業系統和使用者都無法使用.
相反的過程,銷毀線程需要回收資源,也需要一定開銷.
其次,過多的線程將導致過度的切換.
線程切換帶來的效能更是不可估量.系統完成線程切換要經過以下過程:
從使用者模式切換到核心模式.
將CPU寄存器的值儲存到當前線程的核心對象中.
開啟一個自旋鎖,根據調度策略決定下一個要執行的線程.釋放自旋鎖,如果要執行的線程不是同一
進程中的線程,還需要切換虛擬記憶體等進程環境.
將要執行的線程的核心對象的值寫到CPU寄存器中.
切換到使用者模式執行新線程的執行邏輯.
以上開銷對於使用者要執行的任務而言,都是額外的.更不可容忍的是,如果使用者的任務邏輯都是很小
的單元,而新分配線程和線程切換的開銷與任務邏輯需要的開銷的比例可能會10:1,100:1,1000:1.
也就是你花了1000$買的衣服只穿了一天!
所以線程池的目的就是為了減少建立和切換線程的額外開銷,利用已經的線程多次迴圈執行多個任
務從而提高系統的處理能力.也就是在"社會主義初級階段"一件衣服應該盡量多穿一些天數.
[擴充知識]
儘管目前絕大多數JVM實現都是一個Java線程對應一個作業系統線程,但事實上(如果是我來實現JVM)
完全可以用一個作業系統線程執行多個Java線程,因為對於作業系統線程來說Java線程就是一個任務.
而且無論是作業系統線程或Java線程中都可以更細地劃分為超細線程(纖程),即線上程內部實現對纖
程的調度利用纖程來執行任務.