那是一個風和日麗的下午!java
面試官微微一笑,對我說:「小夥子,合理配置線程池你是如何考慮的?」面試
我微微一笑,說出了個人答案:算法
首先確認業務是CPU密集型仍是IO密集型的,數據庫
若是是CPU密集型的,那麼就應該儘可能少的線程數量,通常爲CPU的核數+1;編程
若是是IO密集型:因此可多分配一點 cpu核數*2 也可使用公式:CPU 核數 / (1 - 阻塞係數);其中阻塞係數在 0.8 ~ 0.9 之間。服務器
面試官心想,有點東西,接着追問:「那你是如何獲得的這個公式,或者說你是如何根據CPU核心數肯定線程池併發線程數的」網絡
我心想這不是小瞧我嘛?不屑回答的我脫下了個人帽子併發
哈哈哈哈,進入正題!測試
關於如何計算併發的線程數量,通常分兩派,來自兩本書,且都是好書,線程
第一派:《Java Concurrency in Practice》即《java併發編程實踐》,咱們簡稱A派。
第二派:《Programming Concurrency on the JVM Mastering》即《Java 虛擬機併發編程》,咱們簡稱B派。
到底哪一個是對的?咱們截取書中部份內容具體看看。
A派一書中是這樣寫的
B派一書中是這樣寫的
對於A派,假設CPU跑滿,即撇開CPU使用率這個因素,A派認爲 線程數 = Ncpu * ( 1 + w/c )
大膽假設將B派的公式等於A派公式,
即 Ncpu / (1-阻塞係數) = Ncpu * ( 1 + w/c ) 即 阻塞係數 = 阻塞時間 /(阻塞時間+計算時間),
這個結論在派系二後續中獲得應徵,以下圖:
那麼實際使用中併發線程數如何設置呢?分析以下(咱們以A派公式爲例):
Nthreads = Ncpu * (1+w/c)
IO密集型:通常狀況下,若是存在IO,那麼確定w/c>1(阻塞耗時通常都是計算耗時的不少倍),可是須要考慮系統內存有限(每開啓一個線程都須要內存空間),這裏須要上服務器測試具體多少個線程數適合(CPU佔比、線程數、總耗時、內存消耗)。
若是不想去測試,保守點取1即,Nthreads=Ncpu*(1+1)=2Ncpu。這樣設置通常都OK。
CPU密集型: 假設沒有等待w=0,則W/C=0. Nthreads=Ncpu。
再次概括下:
IO密集型 = 2Ncpu(能夠測試後本身控制大小,2Ncpu通常沒問題)(常出現於線程中:數據庫數據交互、文件上傳下載、網絡數據傳輸等等)
CPU密集型 = Ncpu(常出現於線程中:複雜算法)
java中:Ncpu = Runtime.getRuntime().availableProcessors()
A派的另外一個說法
即對於計算密集型的任務,在擁有N個處理器的系統上,當線程池的大小爲N+1時,一般能實現最優的效率。(即便當計算密集型的線程偶爾因爲缺失故障或者其餘緣由而暫停時,這個額外的線程也能確保CPU的時鐘週期不會被浪費。)
即,計算密集型=Ncpu+1,可是這種作法致使的多一個cpu上下文切換是否值得,這裏不考慮。讀者可本身考量。
本文借鑑概括:Flag Counter 《根據CPU核心數肯定線程池併發線程數》