Java併發程式設計的藝術之九----執行緒池
第一:降低資源消耗。通過重複利用已建立的執行緒降低執行緒建立和銷燬造成的消耗。
第二:提高響應速度。當任務到達時,任務可以不需要等到執行緒建立就能立即執行。
第三:提高執行緒的可管理性。執行緒是稀缺資源,如果無限制地建立,不僅會消耗系統資源,
還會降低系統的穩定性,使用執行緒池可以進行統一分配、調優和監控。但是,要做到合理利用執行緒池,必須對其實現原理了如指掌。
1.執行緒池的實現原理
從圖中可以看出,當提交一個新任務到執行緒池時,執行緒池的處理流程如下。
1)執行緒池判斷核心執行緒池裡的執行緒是否都在執行任務。如果不是,則建立一個新的工作執行緒來執行任務。如果核心執行緒池裡的執行緒都在執行任務,則進入下個流程。
2)執行緒池判斷工作佇列是否已經滿。如果工作佇列沒有滿,則將新提交的任務儲存在這個工作佇列裡。如果工作佇列滿了,則進入下個流程。
3)執行緒池判斷執行緒池的執行緒是否都處於工作狀態。如果沒有,則建立一個新的工作執行緒來執行任務。如果已經滿了,則交給飽和策略來處理這個任務。
Execute方法執行過程
①如果當前執行執行緒少於核心執行緒的容量,就建立新執行緒執行任務(獲取全域性鎖)
②如果執行執行緒等於或多於核心執行緒容量,就將任務加入阻塞佇列
③如果阻塞佇列已滿,建立新執行緒處理任務
④如果超過最大執行緒數maximumPoolSize,任務將被拒絕,呼叫RejectedExecutionHandler.rejectedExecution()方法。
執行execute()方法時,儘可能避免獲取全域性鎖,如果當前執行執行緒數大於等於corePoolSize,幾乎所有的execute方法都是執行步驟2,不需要獲取全域性鎖
工作執行緒:執行緒池建立執行緒時,會將執行緒封裝成工作執行緒worker,worker執行完任務後,還會迴圈獲取工作佇列的任務來執行。
①execute方法建立一個執行緒時,會讓這個執行緒執行當前任務
②這個執行緒執行完上圖1的任務後,會反覆從BlockingQueue獲取任務執行
2.執行緒池的使用
2.1執行緒池的建立
可以通過ThreadPoolExecutor來建立一個執行緒池。
new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, milliseconds, runnableTaskQueue, handler);
①corePoolSize(核心執行緒池的基本大小):當提交一個任務到執行緒池時,執行緒池會建立一個執行緒來執行任務,即使其他空閒的基本執行緒能夠執行新任務也會建立執行緒,等到需要執行的任務數大於核心執行緒池基本大小時就不再建立。
②runnableTaskQueue(任務佇列):用於儲存等待執行的任務的阻塞佇列
ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue、PriorityBlockingQueue無界
③maximumPoolSize:執行緒池允許建立的最大執行緒數。如果佇列滿了,並且已建立的執行緒數小於最大執行緒數,則執行緒池會再建立新的執行緒執行任務。無界佇列沒有效果
④ThreadFactory:用於設定建立執行緒的工廠,可以通過執行緒工廠給每個創建出來的執行緒設定更有意義的名字。
⑤RejectedExecutionHandler(飽和策略):當佇列和執行緒池都滿了,說明執行緒池處於飽和狀態,那麼必須採取一種策略處理提交的新任務。這個策略預設情況下是AbortPolicy,表示無法處理新任務時丟擲異常。
keepAliveTime(執行緒活動保持時間):執行緒池的工作執行緒空閒後,保持存活的時間。所以,如果任務很多,並且每個任務執行的時間比較短,可以調大時間,提高執行緒的利用率。
TimeUnit(執行緒活動保持時間的單位):可選的單位有天(DAYS)、小時(HOURS)、分鐘(MINUTES)、毫秒(MILLISECONDS)、微秒(MICROSECONDS,千分之一毫秒)和納秒(NANOSECONDS,千分之一微秒)
2.2 向執行緒池提交任務
Execute和submit
execute()方法用於提交不需要返回值的任務,所以無法判斷任務是否被執行緒池執行成功。
threadsPool.execute(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
}
});
submit()方法用於提交需要返回值的任務
一個future型別的物件,通過這個future物件可以判斷任務是否執行成功,並且可以通過future的get()方法來獲取返回值,get()方法會阻塞當前執行緒直到任務完成,
2.3執行緒池的監控
TaskCount:執行緒池需要執行的任務數
completeTaskCount:已完成的任務數
largestPoolSize:執行緒池裡曾經建立過的最大執行緒數量
getPoolSize:執行緒池的執行緒數量