CPU個數、核數、線程數、JAVA多線程關係
cpu個數、核數、線程數的關係
cpu個數:是指物理上,也及硬件上的核心數;
核數:是邏輯上的,簡單理解爲邏輯上模擬出的核心數;
線程數:是同一時刻設備能並行執行的程序個數,線程數=cpu個數 * 核數【如果有超線程,再乘以超線程數】
cpu線程數和Java多線程
首先明白幾個概念:
(1) 單個cpu線程在同一時刻只能執行單一指令,也就是一個線程。
(2) 單個線程同時只能在單個cpu線程中執行。
(3) 線程是操作系統最小的調度單位,進程是資源(比如:內存)分配的最小單位。
(4)Java中的所有線程在JVM進程中,CPU調度的是進程中的線程。
(5)Java多線程並不是由於cpu線程數爲多個才稱爲多線程,當Java線程數大於cpu線程數,操作系統使用時間片輪轉(RR)調度算法,頻繁的進行上下文切換,以便併發執行其他線程。
(6)cpu執行Java程序,其根本是執行java代碼編譯後的操作系統可以識別的指令,cpu執行一條指令的時間是ns級別的(1.6G的cpu執行一條指令,大概需要0.6ns),而cpu上下文切換則需要5000-10000個CPU時鐘週期。
(7)受內核限制,Linux系統單個進程最多開啓1000個線程,Windows系統單個進程最多開啓2000個線程。
(8)默認情況下,Java中每創建一個線程,操作系統會分配1M的棧空間。
那麼java多進程,每個進程又多線程,cpu是如何調度的呢?
個人理解:操作系統並不是單純均勻的分配cpu執行不同的進程,因爲線程是調度的最小單位,所以會根據不同進程中的線程個數進行時間分片,均勻的執行每個線程,也就是說A進程中有10個線程,而B進程中有2個線程,那麼cpu分給進程的執行時間理論上應該是5:1才合理。
cpu線程數和java線程數有直接關係嗎?
個人理解:沒有直接關係,正如上面所說,cpu採用分片機制執行線程,給每個線程劃分很小的時間顆粒去執行,但是真正的項目中,一個程序要做很多的的操作,讀寫磁盤、數據邏輯處理、出於業務需求必要的休眠等等操作,當程序在進行I/O操作的時候,線程是阻塞的,線程由運行狀態切換到等待狀態,此時cpu會做上下文切換,以便處理其他的程序;當I/O操作完成後,cpu 會收到一個來自硬盤的中斷信號,並進入中斷處理例程,手頭正在執行的線程因此被打斷,回到 ready 隊列。而先前因 I/O 而waiting 的線程隨着 I/O 的完成也再次回到 就緒 隊列,這時 cpu 可能會選擇它來執行。
如何確定程序最佳線程數?
個人理解:如果所有的任務都是計算密集型的,則創建的多線程數 = 處理器核心數就可以了
如果io操作比較耗時,則根據具體情況調整線程數,此時 多線程數 = n*處理器核心數
一般情況程序線程數等於cpu線程數的兩到三倍就能很好的利用cpu了,過多的程序線程數不但不會提高性能,反而還會因爲線程間的頻繁切換而受影響,具體需要根據線程處理的業務考略,不斷調整線程數個數,確定當前系統最優的線程數。
CPU親和性
瞭解下將進程與 CPU 進行綁定的好處。
進程綁定 CPU 的好處:在多核 CPU 結構中,每個核心有各自的L1、L2緩存,而L3緩存是共用的。如果一個進程在覈心間來回切換,各個核心的緩存命中率就會受到影響。相反如果進程不管如何調度,都始終可以在一個核心上執行,那麼其數據的L1、L2 緩存的命中率可以顯著提高。
所以,將進程與 CPU 進行綁定可以提高 CPU 緩存的命中率,從而提高性能。而進程與 CPU 綁定被稱爲:CPU 親和性。
Java綁定線程到指定核心
使用Java-Thread-Affinity
<!-- https://mvnrepository.com/artifact/net.openhft/Java-Thread-Affinity -->
<dependency>
<groupId>net.openhft</groupId>
<artifactId>Java-Thread-Affinity</artifactId>
<version>3.2.3</version>
</dependency>
代碼:
try (AffinityLock affinityLock = AffinityLock.acquireLock(5)) {
while (true) {
}
}
運行以後可以發現第6個核心滿載100%