線程池的意義
- 循環利用線程資源,避免重復創建和銷毀線程
- 線程池的任務是異步執行的,只要提交完成就能快速返回,可以提高應用響應性
- Java線程池還有一個很重要的意義:Java線程池就是JDK 5 推出的Executor框架,在此之前Java線程既是工作任務又是執行機制,而Executor框架把工作任務與執行機制分離開來:工作任務包括Runnable接口和Callable接口,而執行機制由Executor接口提供。
Executor 類繼承體系
Executor框架由三個部分組成
- 工作任務:Runnable/Callable 接口
- 工作任務就是Runnable/Callable接口的實現,可以被線程池執行
- 執行機制:Executor接口、ExecutorService接口、ScheduledExecutorService接口
- ThreadPoolExecutor 是最核心的線程池實現,用來執行被提交的任務
- ScheduledThreadPoolExecutor 是任務調度的線程池實現,可以在給定的延遲后運行命令,或者定期執行命令(它比Timer更靈活)
- ForkJoinPool是一個並發執行框架
- 異步計算的結果:Future接口
- 實現Future接口的FutureTask類,代表異步計算的結果
線程池的實現原理
線程池的5個重要參數(需記牢):
- workQueue:工作(任務)隊列
- corePoolSize、maximumPoolSize:最小最大線程數
- keepAliveTime:線程存活時間
- threadFactory:線程工廠
- handler:拒絕策略
- 如果運行的線程數少於corePoolSize,創建新線程來處理任務(注意,這一步需要獲取全局鎖)
- 否則,說明線程數大於corePoolSize,將任務插入BlockingQueue
- 如果插入任務失敗(隊列已滿),且運行的線程數少於maximumPoolSize,創建新線程來處理任務(注意,這一步需要獲取全局鎖)
- 否則,說明線程數大於maximumPoolSize,執行拒絕策略
ThreadPoolExecutor 采取上述設計思路,是為了盡可能地避免獲取全局鎖,在完成預熱之后(當前運行的線程數大於等於corePoolSize),則幾乎所有的調用都是執行步驟2,而步驟2不需要獲取全局鎖
關閉線程池
可以調用shutdown()或shutdownNow()來關閉線程池,其中原理是遍歷所有工作線程,然后逐個調用線程的interrupt()來進行中斷。但是它們存在一定的區別,shutdownNow首先將線程池的狀態設置成STOP,然后嘗試停止所有的正在執行或暫停任務的線程,並返回等待執行任務的列表,而shutdown只是將線程池的狀態設置成SHUTDOWN狀態,然后中斷所有沒有正在執行任務的線程。
只要調用了這兩個關閉方法中的任意一個,isShutdown()就會返回true。當所有的任務都關閉后,才表示線程池關閉成功,這時調用isTerminaed()會返回true。至於調用哪一種方法來關閉線程池,應該由線程池的任務特性決定,通常調用shutdown方法來關閉線程池,如果任務不一定要執行完,則可以調用shutdownNow方法