java線程池學習(六) —— 線程池的合理配置

一、確定線程數

在工作中,爲了加快程序的處理速度,我們需要將問題分解成若干個併發執行的任務。接着我們將這些任務委派給線程,以便使它們可以併發的執行。但是需要注意的是,由於資源所限,我們不能創建過多的線程。

這就涉及到一個 確定創建多少線程數纔是合理 的問題。 

《java虛擬機併發編程》一書中,對這個問題有詳盡的解答,本人在此摘取歸納如下:

1.我們可以先獲取到系統可用的處理器核心數:

Runtime.getRuntime().availableProcessors()


2.確定任務的類型:

如果所有任務都是計算密集型的,則創建處理器可用核心數那麼多的線程數就可以了。

在這種情況下,創建更多的線程對程序的性能而言反而是不利的。因爲當有多個任務處於就緒狀態時,處理器核心需要在線程間頻繁進行上下文切換,而這種切換對程序性能損耗較大。

如果任務都是IO密集型的,那麼我們需要開更多的線程來提高性能。

當一個任務執行IO操作時,其線程被阻塞,於是處理器可以立即進行上下文切換以便處理其他就緒線程。如果我們只有處理器可用核心數那麼多線程的話,則即使有待執行的任務也無法處理,因爲我們已經拿不出更多的線程供處理器調度了。


3.計算出程序所需的線程數:

首先我們要明白一個概念叫 阻塞係數

如果任務有50%的時間處於阻塞狀態,則阻塞係數爲0.5。則程序所需的線程數爲處理器可用核心數的兩倍。如果任務被阻塞的時間少於50%,即這些任務是計算密集型的,則程序所需線程數將隨之減少,但最少也不應該低於處理器的核心數。如果任務被阻塞的時間大於執行時間,即該任務是IO密集型的,我們就需要創建比處理器核心數大幾倍數量的線程。

我們可以計算出程序所需線程的總數,總結如下:

線程數 = CPU可用核心數/(1 - 阻塞係數),其中阻塞係數的取值在0和1之間。

計算密集型人物的阻塞係數爲0,而IO密集型任務的阻塞係數則接近1。


二、線程池的監控:

我們可以通過線程池提供的參數進行監控。線程池裏有一些屬性在監控線程池的時候可以使用

  • taskCount:線程池需要執行的任務數量。
  • completedTaskCount:線程池在運行過程中已完成的任務數量。小於或等於taskCount。
  • largestPoolSize:線程池曾經創建過的最大線程數量。通過這個數據可以知道線程池是否滿過。如等於線程池的最大大小,則表示線程池曾經滿了。
  • getPoolSize:線程池的線程數量。如果線程池不銷燬的話,池裏的線程不會自動銷燬,所以這個大小隻增不減。
  • getActiveCount:獲取活動的線程數。

通過擴展線程池進行監控。通過繼承線程池並重寫線程池的beforeExecute,afterExecute和terminated方法,我們可以在任務執行前,執行後和線程池關閉前幹一些事情。如監控任務的平均執行時間,最大執行時間和最小執行時間等。這幾個方法在線程池裏是空方法。如:

protected void beforeExecute(Thread t, Runnable r) { }

參考:《java虛擬機併發編程》一書,《聊聊併發(三)——JAVA線程池的分析和使用
發佈了40 篇原創文章 · 獲贊 32 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章