第一:降低資源消耗。通過重複利用已創建的線程降低線程創建和銷燬造成的消耗。
第二:提高響應速度。當任務到達時,任務可以不需要等到線程創建就能立即執行。
第三:提高線程的可管理性。線程是稀缺資源,如果無限制地創建,不僅會消耗系統資源,
還會降低系統的穩定性,使用線程池可以進行統一分配、調優和監控。但是,要做到合理利用線程池,必須對其實現原理了如指掌。
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:線程池的線程數量