java 並發線程個數的如何確定
java 並發線程個數的確定
本文從控制變量的角度來談決定線程個數的依據。模型很簡單,在實際的生產環境中,情況肯定比下文要復雜的多。要充分的進行測試,以使線程個數為優。
java應用程序大概分為兩種:cpu密集型和io密集型。
cpu密集型
就是指線程大部分時間都在用cpu,一般來說,普通的操作都需要用到cpu,比如計算,讀取,循環,賦值,查詢,排序等等。在最理想的情況下,大牛們建議將線程數設置為count(cpu)+-1
io密集型
io操作一般不需要cpu的參與,線程在io時,線程會被阻塞(線程的六個狀態之一就有Blocked)如果一個線程完成某項工作一共需要100ms,其中io需要80ms,cpu需要20ms(忽略其他時間).那麼線程數應該設立為5.
有鎖的情況
多線程為瞭安全,往往會加鎖。對於關鍵代碼(被頻繁調用的代碼),往往可以成為線程個數的依據之一。
對於全局鎖(比如static上鎖),無論多少個線程,代碼都是串行執行的。這樣線程越多反而越不好。對於鎖粒度的越小,對於線程並發來說越有利。比如ConcurrentHashMap來說,分瞭16個segment,也就是加瞭16把鎖。
在理性的情況下,鎖粒度可以降低16倍,那麼自然可以允許16個並發。最壞的情況是16個線程去爭用一個segment。這個線程的個數需要根據實際情況去調優。
java 線程池線程數量確定思路
多線程可以快速執行任務的原理
因為服務器是擁有多個處理器核心的。運行某進程時,如果隻有一個線程,則隻能調動一個處理器核心,其他處理器核心可能處於空閑狀態。如果是多線程,則可以調用多個處理器核心,用最大效率去處理任務。
創建線程池需要的參數
創建線程池一般需要參數有:核心線程數,最大線程數,線程銷毀時間,任務隊列,拒絕策略等。
線程池裡的線程分為兩種,分別是核心線程和非核心線程。當線程池接收到任務時,會先創建核心線程數去處理任務,直至待處理的任務數量超過任務隊列長度和核心線程數之和時,會繼續創建非核心線程直至最大線程數。
線程池接收到的任務數量在即將超過任務隊列長度和最大線程數之和時,會觸發拒絕策略處理該任務。
非核心線程在執行完成後會立即銷毀,核心線程則會等待設置的銷毀時間後再進行銷毀。
當任務隊列長度足夠大時,核心線程數和最大線程數相等,不然不能觸發到創建非核心線程
確定線程數
線程數計算公式為:
Nthreads=NcpuUcpu(1+w/c) =Ncpu*(1+w/c)
其中 Nthreads:線程數;Ncpu:處理器核心數;Ucpu:處理器的使用百分比;W/C:等待時間與計算時間的比率
Ncpu可以通過以下代碼獲取
Runtime.getRuntime().availableProcessors()
等待時間與計算時間的比率
針對IO密集型的,阻塞耗時w一般都是計算耗時幾倍c,假設阻塞耗時=計算耗時的情況下,Nthreads=Ncpu*(1+1)=2Ncpu。所以這種情況下,考慮2倍的CPU核心數做為線程數
對於計算密集型的,阻塞耗時趨於0,即w/c趨於0,公式Nthreads = Ncpu。
線程數一般是處理器核心數的整數倍。線程數設置過多,在多任務並發情況下,則會影響服務器的整體運行速度;設置過少,則不能最大化應用服務器性能。所以需要根據具體業務來具體調整。
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- 聊一聊concurrenthashmap的size方法原理
- Java ConcurrentHashMap用法案例詳解
- ConcurrentHashMap是如何保證線程安全
- golang中的並發和並行
- Java中ConcurrentHashMap是如何實現線程安全