【Java 多線程】線程池 —— 詳解線程池原理和使用

Java線程池是運用最多的併發框架,學號多線程以及合理的使用多線程可以帶來很大的好處,今天就來一起學習線程池相關的知識吧!

一、線程池的實現原理

當向線程池提交一個任務後,線程池會怎麼做呢?

  1. 首先線程池會在核心線程corePoolSize中找是否都在執行任務,如果不是,就創建一個新的線程來分執行這個任務
  2. 如果核心線程都在執行任務,此時線程池判斷工作隊列BlockingQueue是否已滿,如果沒滿,就把這個任務加到工作隊列中
  3. 如果工作隊列也滿了,線程池就判斷所有線程池中的線程maximumPoolQueue是否都在工作,如果不是,就創建一個新的工作線程來執行任務
  4. 如果都滿了,那就會交給飽和策略去處理這個任務

可以結合流程圖更好理解:
在這裏插入圖片描述
接下來展示一張在線程池中的執行流程圖:
(圖源自《Java併發編程的藝術》)
在這裏插入圖片描述
線程池在線程中執行任務分爲兩種情況:

  • execute()方法中創建一個線程,讓這個線程執行任務
  • 這個線程執行完任務後,回反覆的從BlockingQueue獲取任務來執行

二、使用線程池

1. 使用線程池的好處

在開發中,合理的使用線程池可以帶來很大的好處:

  1. 降低資源消耗,通過重複的利用以及創建的響線程降低線程創建和銷燬的消耗
  2. 提高響應速度,當任務到達時,任務不需要等待線程創建就可以執行
  3. 提高線程的可管理性,如果無線的創建線程,不僅會消耗系統的資源,還會降低系統的穩定性,使用線程池可以進行統一的分配和監控。

2.線程池的創建

我們可以通過ThreadPoolExecutor來創建一個線程池
在這裏插入圖片描述
這是它擁有的構造方法們,我們來看看這些參數分別是什麼:

  1. corePoolSize —— 線程池的基本大小:當提交一個任務到線程池是,線程池會創建一個線程來執行任務,即使其它空閒的基本線程能夠執行新任務也會創建線程,等到任務數大於線程池基本大小時就不再創建。
  2. maximumPoolSize —— 線程池中允許的最大線程數 ,如果任務隊列滿了並且已經創建的線程小於最大線程數,則線程池會再創建新的線程執行任務。
  3. keepAliveTime —— 當線程數大於核心時,這是多餘的空閒線程在終止之前等待新任務的最大時間。 超過這個時間線程就會被終止
  4. unit —— keepAliveTime參數的時間單位 ,可選單位有:天、小時、分鐘、毫秒、微秒、納秒
  5. workQueue —— 在執行任務之前用於保存任務的隊列。 這個隊列只會保存execute方法提交的Runnable任務。
    可以選擇以下幾個阻塞隊列:
    (1) ArrayBlockingQueue: 一個基於數組結構的有界阻塞隊列,按先進先出對元素排序
    (2) LinkedBlockingQueue:一個基於鏈表結構的阻塞隊列,按先進先出排序元素,吞吐量高於ArrayBlockingQueue
    (3)PriorityBlockingQueue:一個具有優先級的無限阻塞隊列
  6. handler —— 執行被阻止時使用的處理程序,因爲達到線程限制和隊列容量
    有以下四種飽和策略(拒絕策略):
    (1)AbortPolicy:直接拋出異常
    (2)CallerRunsPolicy:只用調用者所在的這個線程來運行任務
    (3)DiscardPolicy:不處理,丟棄掉,。如果線程隊列已滿,則後續提交的任務都會被丟棄,且是靜默丟棄。
    (4)DiscardOldestPolicy:丟棄掉隊列中最老的一個任務,執行當前任務
    默認拒絕策略爲AbortPolicy

3. 向線程池提交任務

有兩種方式向線程池提交任務分別是execute()submit()方法
execute()方法用於提交不用返回值的任務,所以無法判斷任務是否被線程池執行成功。它的參數是一個Runnable的實例。
submit()方法用於提交需要返回值的任務。線程會返回一個future類型的對象,通過這個對象可以判斷任務是否執行成功。

4. 關閉線程池

可以通過調用線程池的shutdown()或者shutdownNow()來關閉線程池,它的原理是遍歷線程池中所有的線程,然後逐個調用線程的interrupt()方法中斷線程,所以無法響應中斷的任務有可能永遠無法終止。
二者的區別是:
shutdownNow()首先iang線程池的狀態設爲STOP,然後嘗試停止所有正在執行或暫停的線程,並返回等待執行任務的列表。
shutdown()知識將線程池的狀態設置爲SHUTDOWN,然後中斷所有沒有正在執行的任務。

通常調用shutdown()方法關閉線程池,如果線程池中的任務不一定要執行完,可以調用shutdownNow()方法。

嘮嘮叨叨
這就是線程池的一些基本知識,更多的還是要在實踐中慢慢體會,本文參考《Java併發編程的藝術》一書,有任何問題歡迎評論指正,也歡迎點贊關注一起進步。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章