摘要
首先要明確為什麼要使用線程池,使用線程池會帶來什麼好處?
- 線程是稀缺資源,不能頻繁的創建。
- 應當將其放入一個池子中,可以給其他任務進行復用。
- 解耦作用,線程的創建與執行完全分開,方便維護。
創建一個線程池
以一個使用較多的
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<runnable> workQueue, RejectedExecutionHandler handler)
/<runnable>
參數說明:
- 其中的 corePoolSize 為線程池的基本大小。
- maximumPoolSize 為線程池最大線程大小。
- keepAliveTime 和 unit 則是線程空閒後的存活時間。
- workQueue 用於存放任務的阻塞隊列。
- handler 當隊列和最大線程池都滿了之後的飽和策略。
處理流程
當提交一個任務到線程池時它的執行流程是怎樣的呢?
首先第一步會判斷核心線程數有沒有達到上限,如果沒有則創建線程(會獲取全局鎖),滿了則會將任務丟進阻塞隊列。
如果隊列也滿了則需要判斷最大線程數是否達到上限,如果沒有則創建線程(獲取全局鎖),如果最大線程數也滿了則會根據飽和策略處理。
常用的飽和策略有:
- 直接丟棄任務。
- 調用者線程處理。
- 丟棄隊列中的最近任務,執行當前任務。
所以當線程池完成預熱之後都是將任務放入隊列,接著由工作線程一個個從隊列裡取出執行。
合理配置線程池
線程池並不是配置越大越好,而是要根據任務的熟悉來進行劃分: 如果是 CPU 密集型任務應當分配較少的線程,比如 CPU 個數相當的大小。
如果是 IO 密集型任務,由於線程並不是一直在運行,所以可以儘可能的多配置線程,比如 CPU 個數 * 2 。
當是一個混合型任務,可以將其拆分為 CPU 密集型任務以及 IO 密集型任務,這樣來分別配置。
更多內容請關注每日編程,每天進步一點。
閱讀更多 每日編程 的文章