Java併發編程的藝術(六)——線程池

我們爲什麼要使用線程池?

顧名思義,線程池就是一個存放了很多線程的“池”,就像糧倉一樣,每次我們需要使用線程的時候都可以先去“池子”裏看看有沒有空閒的線程,如果有直接拿出來用就可以了。

爲什麼要提前準備好這些線程並把他們存儲起來呢?

因爲對於系統來說創建和銷燬線程是非常消耗資源的,如果我們提前把一定數量的線程創建好並存儲起來(不進行銷燬),那麼系統一旦到需要使用線程的時候就不需要重新創建了,而是到存儲線程的地方取出一個線程資源進行使用,用完了再把該資源歸還存儲的地方,從而避免了不斷創建銷燬線程的過程,節約了大量的系統資源。

所以在需要異步或者併發執行任務的程序中都可以使用線程池來提高執行效率,但是在使用線程池的時候需要對實際業務進行評估,合理的設置線程池中線程的數量才能達到事半功倍的效果。

一個線程池可以說被劃分爲4個部分,分別是核心線程池,線程池,任務隊列,以及異常處理。具體可以參考以下線程池的結構組成與主要處理過程:
在這裏插入圖片描述

上圖中的1,2,3,4序號爲線程池主要處理過程順序,其處理邏輯順序下圖所示(線程池處理邏輯圖)

在這裏插入圖片描述

有了一定的理論知識,我們就可以深入到編程語言中看看如何使用線程池。

Java中線程池的創建是如何實現的呢?

在Java中通常使用ThreadPoolExecutor 來創建新的線程池
在這裏插入圖片描述

線程池常用參數解釋:

corePoolSize: 核心線程池中線程數量
maximumPoolSize: 線程池中能容納的最大線程數量
keepAliveTime: 線程存活時間
TimeUnit: 存活時間單位
workQueue: 該隊列用來暫時存儲未被執行的線程

我們可以根據業務的實際需求來設置線程數量,以及採用何種隊列作爲存儲隊列。這裏就涉及到如何比較準確的設置線程池的線程數量。

如何設置線程池大小?

系統的性質一般可分爲:CPU密集型、IO密集型與混合型,對於不同類型的任務需要具體問題具體分析,設置不同大小的線程池。

CPU密集型任務

儘量使用較小的線程池,一般爲CPU核心數+1。
因爲CPU密集型任務使得CPU使用率很高,若開過多的線程數,只能增加上下文切換的次數,因此會帶來額外的開銷。

IO密集型任務

可以使用稍大的線程池,一般爲2*CPU核心數。
IO密集型任務CPU使用率並不高,因此可以讓CPU在等待IO的時候去處理別的任務,充分利用CPU時間。

混合型任務

可以將任務分成IO密集型和CPU密集型任務,然後分別用不同的線程池去處理。
只要分完之後兩個任務的執行時間相差不大,那麼就會比串行執行來的高效。
因爲如果劃分之後兩個任務執行時間相差甚遠,那麼先執行完的任務就要等後執行完的任務,最終的時間仍然取決於後執行完的任務,而且還要加上任務拆分與合併的開銷,反而沒有好的結果。

所以在開發的時候不能盲目的使用技術,要結合具體情況具體的需求進行分析,選擇合適的技術,再好的武器用的恰當才能發揮出最大的能量:)

Java併發編程模塊的內容到這裏就告一段落了,回看過去寫的收穫滿滿,後期如果有補充的知識點我會另外完善,微信公衆號和本人的CSDN博客同步更新,歡迎小夥伴們提出建設性意見。接下來想擼一手Spring或者Mybatis的知識點了

在這裏插入圖片描述

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