我的编程空间,编程开发者的网络收藏夹
学习永远不晚

java怎么绑定CPU的线程

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

java怎么绑定CPU的线程

这篇文章主要介绍“java怎么绑定CPU的线程”,在日常操作中,相信很多人在java怎么绑定CPU的线程问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”java怎么绑定CPU的线程”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

简介

在现代计算机系统中,可以有多个CPU,每个CPU又可以有多核。为了充分利用现代CPU的功能,JAVA中引入了多线程,不同的线程可以同时在不同CPU或者不同CPU核中运行。但是对于JAVA程序猿来说创建多少线程是可以自己控制的,但是线程到底运行在哪个CPU上,则是一个黑盒子,一般来说很难得知。

但是如果是不同CPU核对同一线程进行调度,则可能会出现CPU切换造成的性能损失。一般情况下这种损失是比较小的,但是如果你的程序特别在意这种CPU切换带来的损耗,那么可以试试今天要讲的Java Thread Affinity.

Java Thread Affinity简介

java thread Affinity是用来将JAVA代码中的线程绑定到CPU特定的核上,用来提升程序运行的性能。

很显然,要想和底层的CPU进行交互,java thread Affinity一定会用到JAVA和native方法进行交互的方法,JNI虽然是JAVA官方的JAVA和native方法进行交互的方法,但是JNI在使用起来比较繁琐。所以java thread Affinity实际使用的是JNA,JNA是在JNI的基础上进行改良的一种和native方法进行交互的库。

先来介绍CPU中几个概念,分别是CPU,CPU socket和CPU core。

首先是CPU,CPU的全称就是central processing unit,又叫做中央处理器,就是用来进行任务处理的关键核心。

那么什么是CPU socket呢?所谓socket就是插CPU的插槽,如果组装过台式机的同学应该都知道,CPU就是安装在Socket上的。

CPU Core指的是CPU中的核数,在很久之前CPU都是单核的,但是随着多核技术的发展,一个CPU中可以包含多个核,而CPU中的核就是真正的进行业务处理的单元。

如果你是在linux机子上,那么可以通过使用lscpu命令来查看系统的CPU情况,如下所示:

Architecture:          x86_64CPU op-mode(s):        32-bit, 64-bitByte Order:            Little EndianCPU(s):                1On-line CPU(s) list:   0Thread(s) per core:    1Core(s) per socket:    1Socket(s):             1NUMA node(s):          1Vendor ID:             GenuineIntelCPU family:            6Model:                 94Model name:            Intel(R) Xeon(R) Gold 6148 CPU @ 2.40GHzStepping:              3CPU MHz:               2400.000BogoMIPS:              4800.00Hypervisor vendor:     KVMVirtualization type:   fullL1d cache:             32KL1i cache:             32KL2 cache:              4096KL3 cache:              28160KNUMA node0 CPU(s):     0Flags:                 fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl eagerfpu pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch invpcid_single fsgsbase bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx avx512f avx512dq rdseed adx smap avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 arat

从上面的输出我们可以看到,这个服务器有一个socket,每个socket有一个core,每个core可以同时处理1个线程。

这些CPU的信息可以称为CPU layout。在linux中CPU的layout信息是存放在/proc/cpuinfo中的。

在Java Thread Affinity中有一个CpuLayout接口用来和这些信息进行对应:

public interface CpuLayout {        int cpus();    int sockets();    int coresPerSocket();    int threadsPerCore();    int socketId(int cpuId);    int coreId(int cpuId);    int threadId(int cpuId);}

根据CPU layout的信息, AffinityStrategies提供了一些基本的Affinity策略,用来安排不同的thread之间的分布关系,主要有下面几种:

    SAME_CORE - 运行在同一个core中。    SAME_SOCKET - 运行在同一个socket中,但是不在同一个core上。    DIFFERENT_SOCKET - 运行在不同的socket中    DIFFERENT_CORE - 运行在不同的core上    ANY - 任何情况都可以

这些策略也都是根据CpuLayout的socketId和coreId来进行区分的,我们以SAME_CORE为例,按下它的具体实现:

SAME_CORE {        @Override        public boolean matches(int cpuId, int cpuId2) {            CpuLayout cpuLayout = AffinityLock.cpuLayout();            return cpuLayout.socketId(cpuId) == cpuLayout.socketId(cpuId2) &&                    cpuLayout.coreId(cpuId) == cpuLayout.coreId(cpuId2);        }    }

Affinity策略可以有顺序,在前面的策略会首先匹配,如果匹配不上则会选择第二策略,依此类推。

AffinityLock的使用

接下来我们看下Affinity的具体使用,首先是获得一个CPU的lock,在JAVA7之前,我们可以这样写:

AffinityLock al = AffinityLock.acquireLock();try {     // do some work locked to a CPU.} finally {     al.release();}

在JAVA7之后,可以这样写:

try (AffinityLock al = AffinityLock.acquireLock()) {    // do some work while locked to a CPU.}

acquireLock方法可以为线程获得任何可用的cpu。这个是一个粗粒度的lock。如果想要获得细粒度的core,可以用acquireCore:

try (AffinityLock al = AffinityLock.acquireCore()) {    // do some work while locked to a CPU.}

acquireLock还有一个bind参数,表示是否将当前的线程绑定到获得的cpu lock上,如果bind参数=true,那么当前的thread会在acquireLock中获得的CPU上运行。如果bind参数=false,表示acquireLock会在未来的某个时候进行bind。

上面我们提到了AffinityStrategy,这个AffinityStrategy可以作为acquireLock的参数使用:

public AffinityLock acquireLock(AffinityStrategy... strategies) { return acquireLock(false, cpuId, strategies);    }

通过调用当前AffinityLock的acquireLock方法,可以为当前的线程分配和之前的lock策略相关的AffinityLock。

AffinityLock还提供了一个dumpLocks方法,用来查看当前CPU和thread的绑定状态。我们举个例子:

private static final ExecutorService ES = Executors.newFixedThreadPool(4,           new AffinityThreadFactory("bg", SAME_CORE, DIFFERENT_SOCKET, ANY));for (int i = 0; i < 12; i++)            ES.submit(new Callable<Void>() {                @Override                public Void call() throws InterruptedException {                    Thread.sleep(100);                    return null;                }            });        Thread.sleep(200);        System.out.println("\nThe assignment of CPUs is\n" + AffinityLock.dumpLocks());        ES.shutdown();        ES.awaitTermination(1, TimeUnit.SECONDS);

上面的代码中,我们创建了一个4个线程的线程池,对应的ThreadFactory是AffinityThreadFactory,给线程池起名bg,并且分配了3个AffinityStrategy。 意思是首先分配到同一个core上,然后到不同的socket上,最后是任何可用的CPU。

然后具体执行的过程中,我们提交了12个线程,但是我们的Thread pool最多只有4个线程,可以预见, AffinityLock.dumpLocks方法返回的结果中只有4个线程会绑定CPU,一起来看看:

The assignment of CPUs is0: CPU not available1: Reserved for this application2: Reserved for this application3: Reserved for this application4: Thread[bg-4,5,main] alive=true5: Thread[bg-3,5,main] alive=true6: Thread[bg-2,5,main] alive=true7: Thread[bg,5,main] alive=true

从输出结果可以看到,CPU0是不可用的。其他7个CPU是可用的,但是只绑定了4个线程,这和我们之前的分析是匹配的。

接下来,我们把AffinityThreadFactory的AffinityStrategy修改一下,如下所示:

new AffinityThreadFactory("bg", SAME_CORE)

表示线程只会绑定到同一个core中,因为在当前的硬件中,一个core同时只能支持一个线程的绑定,所以可以预见最后的结果只会绑定一个线程,运行结果如下:

The assignment of CPUs is
0: CPU not available
1: Reserved for this application
2: Reserved for this application
3: Reserved for this application
4: Reserved for this application
5: Reserved for this application
6: Reserved for this application
7: Thread[bg,5,main] alive=true

可以看到只有第一个线程绑定了CPU,和之前的分析相匹配。

使用API直接分配CPU

上面我们提到的AffinityLock的acquireLock方法其实还可以接受一个CPU id参数,直接用来获得传入CPU id的lock。这样后续线程就可以在指定的CPU上运行。

    public static AffinityLock acquireLock(int cpuId) {        return acquireLock(true, cpuId, AffinityStrategies.ANY);    }

实时上这种Affinity是存放在BitSet中的,BitSet的index就是cpu的id,对应的value就是是否获得锁。

先看下setAffinity方法的定义:

    public static void setAffinity(int cpu) {        BitSet affinity = new BitSet(Runtime.getRuntime().availableProcessors());        affinity.set(cpu);        setAffinity(affinity);    }

再看下setAffinity的使用:

long currentAffinity = AffinitySupport.getAffinity();Affinity.setAffinity(1L << 5); // lock to CPU 5.

注意,因为BitSet底层是用Long来进行数据存储的,所以这里的index是bit index,所以我们需要对十进制的CPU index进行转换。

到此,关于“java怎么绑定CPU的线程”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

java怎么绑定CPU的线程

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

java怎么绑定CPU的线程

这篇文章主要介绍“java怎么绑定CPU的线程”,在日常操作中,相信很多人在java怎么绑定CPU的线程问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”java怎么绑定CPU的线程”的疑惑有所帮助!接下来,请跟
2023-06-30

C#线程绑定ThreadLocal类怎么使用

本篇内容主要讲解“C#线程绑定ThreadLocal类怎么使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C#线程绑定ThreadLocal类怎么使用”吧!在.Net 4.0的Thread里,
2023-07-02

WPF怎么绑定多条曲线

在WPF中,可以使用Path对象来绑定多条曲线。具体的步骤如下:1. 创建一个Path对象,并将其添加到XAML文件中的Canvas或Grid等容器中。```xml```2. 在Path对象的Data属性中,使用GeometryGroup对
2023-08-20

Java多线程导致CPU占用100%怎么办

这篇文章给大家分享的是有关Java多线程导致CPU占用100%怎么办的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。简介情景:1000万表数据导入内存数据库,按分页大小10000查询,多线程,15条线程跑。使用了E
2023-06-15

java怎么定义线程类

在Java中,可以通过以下步骤来定义一个线程类:1. 创建一个类,并让它继承自Thread类。2. 在类中重写Thread类的run()方法,该方法包含了线程的执行逻辑。3. 在run()方法中编写线程的具体逻辑。4. 可以在类中添加其他方
2023-08-08

如何定位java程序中占用cpu最高的线程堆栈信息

这篇文章主要介绍了如何定位java程序中占用cpu最高的线程堆栈信息方法的相关资料,需要的朋友可以参考下
2022-11-13

Java中怎么自定义线程池

本篇文章给大家分享的是有关Java中怎么自定义线程池,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。Java代码ThreadPoolExecutor public Threa
2023-06-17

java并发线程个数的怎么确定

本篇内容主要讲解“java并发线程个数的怎么确定”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“java并发线程个数的怎么确定”吧!java 并发线程个数的确定本文从控制变量的角度来谈决定线程个数
2023-06-22

java动态绑定怎么理解

这篇文章主要介绍“java动态绑定怎么理解”,在日常操作中,相信很多人在java动态绑定怎么理解问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”java动态绑定怎么理解”的疑惑有所帮助!接下来,请跟着小编一起来
2023-06-30

怎么在Java中自定义线程池

这篇文章给大家介绍怎么在Java中自定义线程池,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。【1】接口定义public interface IThreadPool { /**
2023-06-06

java怎么自定义并发线程池

要自定义并发线程池,可以使用`ThreadPoolExecutor`类来实现。`ThreadPoolExecutor`是`ExecutorService`接口的一个实现类,可以用来创建和管理线程池。以下是一个自定义并发线程池的示例:im
2023-10-25

Java中怎么固定线程池大小

今天就跟大家聊聊有关Java中怎么固定线程池大小,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。固定大小的Java线程池Java线程池代码import java.util.concur
2023-06-17

Java怎么自定义线程池中队列

本篇内容介绍了“Java怎么自定义线程池中队列”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!背景业务交互的过程中涉及到了很多关于SFTP下载
2023-07-02

linux程序怎么绑定硬件id

在Linux中,可以使用udev规则来绑定硬件设备的ID。udev是Linux中的设备管理系统,它负责在设备插入或移除时进行设备检测和配置。通过编写udev规则,可以在设备插入时执行特定的操作。下面是一个示例udev规则的结构:SUBSYS
2023-10-18

java怎么停止线程池中的线程

要停止线程池中的线程,可以使用 `ExecutorService` 接口提供的 `shutdown()` 方法来停止线程池。这个方法会平滑地关闭线程池,即等待所有已提交的任务执行完毕后关闭线程池。示例代码如下:```ExecutorServ
2023-08-20

jQuery中on绑定的事件怎么解绑

这篇文章主要介绍了jQuery中on绑定的事件怎么解绑的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇jQuery中on绑定的事件怎么解绑文章都会有所收获,下面我们一起来看看吧。解绑单个事件在jQuery中,我们
2023-07-05

怎么在Linux中使用Shell脚本查看Java线程的CPU使用情况

这篇文章主要介绍“怎么在Linux中使用Shell脚本查看Java线程的CPU使用情况”,在日常操作中,相信很多人在怎么在Linux中使用Shell脚本查看Java线程的CPU使用情况问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作
2023-06-09

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录