欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

java高級用法之綁定CPU的線程Thread?Affinity簡介

 更新時間:2022年05月11日 17:25:42   作者:flydean程序那些事  
java線程thread affinity是用來將java代碼中的線程綁定到CPU特定的核上,用來提升程序運行的性能,這篇文章主要介紹了java高級用法之綁定CPU的線程thread affinity的相關知識,需要的朋友可以參考下

簡介

在現(xiàn)代計算機系統(tǒng)中,可以有多個CPU,每個CPU又可以有多核。為了充分利用現(xiàn)代CPU的功能,JAVA中引入了多線程,不同的線程可以同時在不同CPU或者不同CPU核中運行。但是對于JAVA程序猿來說創(chuàng)建多少線程是可以自己控制的,但是線程到底運行在哪個CPU上,則是一個黑盒子,一般來說很難得知。

但是如果是不同CPU核對同一線程進行調(diào)度,則可能會出現(xiàn)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中的核數(shù),在很久之前CPU都是單核的,但是隨著多核技術的發(fā)展,一個CPU中可以包含多個核,而CPU中的核就是真正的進行業(yè)務處理的單元。

如果你是在linux機子上,那么可以通過使用lscpu命令來查看系統(tǒng)的CPU情況,如下所示:

Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                1
On-line CPU(s) list:   0
Thread(s) per core:    1
Core(s) per socket:    1
Socket(s):             1
NUMA node(s):          1
Vendor ID:             GenuineIntel
CPU family:            6
Model:                 94
Model name:            Intel(R) Xeon(R) Gold 6148 CPU @ 2.40GHz
Stepping:              3
CPU MHz:               2400.000
BogoMIPS:              4800.00
Hypervisor vendor:     KVM
Virtualization type:   full
L1d cache:             32K
L1i cache:             32K
L2 cache:              4096K
L3 cache:              28160K
NUMA node0 CPU(s):     0
Flags:                 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);
}

根據(jù)CPU layout的信息, AffinityStrategies提供了一些基本的Affinity策略,用來安排不同的thread之間的分布關系,主要有下面幾種:

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

這些策略也都是根據(jù)CpuLayout的socketId和coreId來進行區(qū)分的,我們以SAME_CORE為例,按下它的具體實現(xiàn):

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參數(shù),表示是否將當前的線程綁定到獲得的cpu lock上,如果bind參數(shù)=true,那么當前的thread會在acquireLock中獲得的CPU上運行。如果bind參數(shù)=false,表示acquireLock會在未來的某個時候進行bind。

上面我們提到了AffinityStrategy,這個AffinityStrategy可以作為acquireLock的參數(shù)使用:

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

通過調(diào)用當前AffinityLock的acquireLock方法,可以為當前的線程分配和之前的lock策略相關的AffinityLock。

AffinityLock還提供了一個dumpLocks方法,用來查看當前CPU和thread的綁定狀態(tài)。我們舉個例子:

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);

上面的代碼中,我們創(chuàng)建了一個4個線程的線程池,對應的ThreadFactory是AffinityThreadFactory,給線程池起名bg,并且分配了3個AffinityStrategy。 意思是首先分配到同一個core上,然后到不同的socket上,最后是任何可用的CPU。

然后具體執(zhí)行的過程中,我們提交了12個線程,但是我們的Thread pool最多只有4個線程,可以預見, AffinityLock.dumpLocks方法返回的結果中只有4個線程會綁定CPU,一起來看看:

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: Thread[bg-4,5,main] alive=true
5: Thread[bg-3,5,main] alive=true
6: Thread[bg-2,5,main] alive=true
7: 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參數(shù),直接用來獲得傳入CPU id的lock。這樣后續(xù)線程就可以在指定的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來進行數(shù)據(jù)存儲的,所以這里的index是bit index,所以我們需要對十進制的CPU index進行轉換。

總結

Java Thread Affinity可以從JAVA代碼中對程序中Thread使用的CPU進行控制,非常強大,大家可以運用起來。

到此這篇關于java高級用法之綁定CPU的線程Thread-Affinity的文章就介紹到這了,更多相關java線程Thread-Affinity內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Java基礎:徹底搞懂java多線程

    Java基礎:徹底搞懂java多線程

    篇文章主要介紹了Java多線程的相關資料,幫助大家更好的理解和學習Java線程相關知識,感興趣的朋友可以了解下,希望能給你帶來幫助
    2021-08-08
  • Java構造器(構造方法)與方法區(qū)別說明

    Java構造器(構造方法)與方法區(qū)別說明

    這篇文章主要介紹了Java構造器(構造方法)與方法區(qū)別說明,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • SpringBoot @FixMethodOrder 如何調(diào)整單元測試順序

    SpringBoot @FixMethodOrder 如何調(diào)整單元測試順序

    這篇文章主要介紹了SpringBoot @FixMethodOrder 調(diào)整單元測試順序方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • 一文帶你掌握Java中的HashSet

    一文帶你掌握Java中的HashSet

    HashSet?基于?HashMap?來實現(xiàn)的,是一個不允許有重復元素的集合,HashSet?不是線程安全的,?如果多個線程嘗試同時修改?HashSet,則最終結果是不確定的,本文將帶你詳細了解Java中的HashSet,,需要的朋友可以參考下
    2023-05-05
  • Java實現(xiàn)用位運算維護狀態(tài)碼

    Java實現(xiàn)用位運算維護狀態(tài)碼

    位運算是一種非常高效的運算方式,在算法考察中比較常見,那么業(yè)務代碼中我們?nèi)绾问褂梦贿\算呢,感興趣的小伙伴快跟隨小編一起學習一下吧
    2024-03-03
  • 怎樣將一個JAR包添加到Java應用程序的Boot?Classpath中

    怎樣將一個JAR包添加到Java應用程序的Boot?Classpath中

    本文文章給大家介紹如何將一個JAR包添加到Java應用程序的Boot?Classpath中,本文通過實例代碼給大家介紹的非常詳細,需要的的朋友參考下吧
    2023-11-11
  • Spring MVC文件配置以及參數(shù)傳遞示例詳解

    Spring MVC文件配置以及參數(shù)傳遞示例詳解

    這篇文章主要給大家介紹了關于Spring MVC文件配置以及參數(shù)傳遞的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-03-03
  • 如何用Java Stream寫出既高雅又裝*的代碼

    如何用Java Stream寫出既高雅又裝*的代碼

    如何讓同事看不懂你寫的代碼,然后覺得你非常牛逼,這里用到了stream()與Lambda,需要有點基礎,沒基礎你炫個&#128296;優(yōu)雅永不過時~ 看下面文章時記得穿燕尾服,拿高腳杯
    2021-08-08
  • mybatis如何對大量數(shù)據(jù)的游標查詢

    mybatis如何對大量數(shù)據(jù)的游標查詢

    這篇文章主要介紹了mybatis如何對大量數(shù)據(jù)的游標查詢問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • java對接支付寶支付項目的實戰(zhàn)記錄

    java對接支付寶支付項目的實戰(zhàn)記錄

    最近公司有一個需求是接入第三方支付(微信&支付寶),我接到了支付寶支付,所以下面這篇文章主要給大家介紹了關于java對接支付寶支付項目的相關資料,需要的朋友可以參考下
    2022-06-06

最新評論