1. 程式人生 > >【Java】執行緒池

【Java】執行緒池

概念

執行緒池好處

  1. 降低資源消耗:重複利用執行緒,從而降低建立和銷燬造成的消耗

  2. 提高響應速度:任務到達時,可以不需要等到執行緒建立就能立即執行

  3. 提高執行緒的可管理性:執行緒會耗盡資源,降低穩定性,執行緒池可以統一分配、調優、監控

執行緒池組成

  1. 執行緒池管理器(ThreadPool):用於建立並管理執行緒池,包括 建立執行緒池,銷燬執行緒池,新增新任務

  2. 工作執行緒(PoolWorker):執行緒池中執行緒,在沒有任務時處於等待狀態,可以迴圈的執行任務

  3. 任務介面(Task):每個任務必須實現的介面,以供工作執行緒排程任務的執行,它主要規定了任務的入口,任務執行完後的收尾工作,任務的執行狀態等

  4. 任務佇列(taskQueue):用於存放沒有處理的任務,提供一種緩衝機制。

執行緒池實現原理

這裡寫圖片描述

  1. 提交執行緒後,執行緒池判斷核心執行緒池裡是否都在執行任務。(如果不是,則建立一個新的工作執行緒來執行任務;如果是,進入下一個流程)

  2. 執行緒池判斷工作佇列是否已滿。(如果沒有滿,將新提交任務儲存在工作佇列;如果已滿,進入下一個流程)

  3. 執行緒池判斷執行緒池的執行緒是否都處於工作狀態。(如果沒有,建立一個新的工作執行緒執行任務;如果已滿,則交給飽和策略處理這個任務)

ThreadPoolExecutor 執行 execute 情況

  1. 如果當前執行執行緒 < corePoolSize,則建立新執行緒來執行任務

  2. 如果執行執行緒 >= corePoolSize,則將任務加入 BlockingQueue

  3. 如果 BlockIngQueue 佇列已滿,則建立新的執行緒來處理任務

  4. 如果建立新執行緒將使當前執行執行緒超出 maximumPoolSize,任務將被拒絕,並呼叫 RejectExecutionHandler.rejectedExecution() 方法

執行緒池使用

corePoolSize

執行緒池中的核心執行緒數,提交一個任務到執行緒池時,會建立一個執行緒執行任務(即使其他執行緒空閒),直到執行執行緒數等於執行緒池基本大小則不再建立

runnableTaskQueue

任務佇列,儲存等待執行的任務的阻塞佇列,有如下阻塞佇列

  • ArrayBlockingQueue:基於陣列結構的有界阻塞佇列,按 FIFO原則排序元素
  • LinkedBlockingQueue:基於連結串列結構的阻塞佇列,按FIFO排序元素,吞吐量高於 ArrayBlockingQueue
  • SynchronousQueue:不儲存元素的阻塞佇列,插入操作必須等到上一個執行緒呼叫移除操作,吞吐量高於 LinkedBlockingQueue
  • PriorityBlockingQueue:具有優先順序的無限阻塞佇列

maximumPoolSize

執行緒池的最大執行緒數,如果佇列滿了,並且建立的執行緒數小於最大執行緒數,則建立新執行緒執行任務。如果使用了無界的任務佇列此引數無效

threadFactory

設定建立執行緒的工廠,通過執行緒工廠給每個創建出來的執行緒設定有意義的名字、優先順序

RejectExecutionHandler

飽和策略,當執行執行緒數已達到maximumPoolSize,佇列也已經裝滿時會呼叫該引數拒絕任務,預設實現為 AbortPolicy

  • AbortPolicy:直接丟擲異常
  • CallerRunsPolicy:只用呼叫者所線上程來執行任務
  • DiscardOldestPolicy:丟棄佇列裡最近的一個任務,並執行當前任務
  • DiscardPolicy:不處理,丟棄掉

keepAliveTime

執行緒池中的執行緒存活時間(沒有任務執行時的回收時間),如果任務很多,並且每個任務執行時間短,可以調大時間,提高執行緒的利用率

TimeUnit

執行緒活動保持時間的單位,可選單位有天、小時、分鐘、毫秒、微秒、納秒

提交任務

  • execute() 提交:提交不需要返回值的任務
  • submit() 提交:執行緒池會返回一個 future 物件

關閉執行緒池

遍歷執行緒池中的工作執行緒,逐個呼叫執行緒的 interrupt 方法來中斷執行緒

shutdowNow:將執行緒池狀態設定為 STOP,嘗試停止所有執行緒,並返回等待執行任務的列表

shutdown:只是將執行緒池狀態設定為 SHUTDOWN,中斷沒有正在執行任務的任務

執行緒池合理配置

  1. CPU密集型任務:配置 N+1 個執行緒的執行緒池(N為CPU數量)

  2. IO密集型任務:配置 2N 個執行緒的執行緒池(N為CPU數量)

  3. 優先順序不同的任務可以使用優先順序佇列來處理

  4. 執行時間不同的任務可以交給不同規模的執行緒池來處理,讓執行時間短的任務先執行

  5. 依賴資料庫連線池的任務,因為等待時間長,所以執行緒數應該設定大,更好利用CPU

  6. 儘量使用有界佇列,提高系統的穩定性和預警能力

執行緒池監控

通過擴充套件執行緒池進行監控。可以通過繼承執行緒池來自定義執行緒池,重寫執行緒池的 beforeExecute、afterExecute、terminated 方法。

  • taskCount:執行緒池需要執行的任務數量
  • completedTaskCount:在執行過程中已完成的任務數量
  • largestPoolSize:執行緒池裡曾建立過的最大執行緒數量,可以瞭解執行緒池是否滿過
  • getPoolSize:執行緒池的執行緒數量,執行緒池不銷燬,該值只增不減
  • getActiveCount:獲取活動的執行緒數