JAVA 绑定线程到指定CPU上
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%