Home > Java > Java Tutorial > body text

How to bind thread to specific CPU in Java?

WBOY
Release: 2023-05-09 23:58:17
forward
1953 people have browsed it

Introduction

In modern computer systems, there can be multiple CPUs, and each CPU can have multiple cores. In order to make full use of the functions of modern CPUs, multi-threading was introduced in JAVA. Different threads can run in different CPUs or different CPU cores at the same time. But for JAVA programmers, they can control how many threads they create, but which CPU the threads run on is a black box, and it is generally difficult to know.

But if different CPU cores schedule the same thread, there may be performance losses caused by CPU switching. Under normal circumstances, this loss is relatively small, but if your program is particularly concerned about the loss caused by this kind of CPU switching, then you can try the Java Thread Affinity that I will talk about today.

Introduction to Java Thread Affinity

java thread Affinity is used to bind threads in JAVA code to specific cores of the CPU to improve program running performance.

Obviously, if you want to interact with the underlying CPU, java thread Affinity will definitely use JAVA and native methods to interact. Although JNI is JAVA’s official method for interacting with native methods, JNI is relatively cumbersome to use. Therefore, java thread Affinity actually uses JNA. JNA is a library that is improved on the basis of JNI and interacts with native methods.

Let’s first introduce several concepts in CPU, namely CPU, CPU socket and CPU core.

The first is the CPU. The full name of the CPU is the central processing unit, also called the central processing unit, which is the key core used for task processing.

So what is a CPU socket? The so-called socket is the slot where the CPU is inserted. If you have assembled a desktop computer, you should know that the CPU is installed on the socket.

CPU Core refers to the number of cores in the CPU. A long time ago, CPUs were single-core. However, with the development of multi-core technology, a CPU can contain multiple cores, and the cores in the CPU are The real unit for business processing.

If you are on a Linux machine, you can use the lscpu command to check the CPU status of the system, as shown below:

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
Copy after login

From the above output, we can see that this server has A socket, each socket has a core, and each core can process 1 thread at the same time.

This CPU information can be called CPU layout. In Linux, the CPU layout information is stored in /proc/cpuinfo.

There is a CpuLayout interface in Java Thread Affinity to correspond to this information:

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

According to the CPU layout information, AffinityStrategies provides some basic Affinity strategies to arrange different The distribution relationships between threads mainly include the following:

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

These strategies are also distinguished based on the socketId and coreId of CpuLayout. We take SAME_CORE as an example and press its specific implementation:

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);
        }
    }
Copy after login

Affinity strategies can be in order. The previous strategy will be matched first. If it does not match, the second strategy will be selected, and so on.

Use of AffinityLock

Next let’s look at the specific use of Affinity. The first is to obtain a CPU lock. Before JAVA7, we could write like this:

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

In After JAVA7, you can write like this:

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

acquireLock method can obtain any available cpu for the thread. This is a coarse-grained lock. If you want to obtain fine-grained core, you can use acquireCore:

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

acquireLock also has a bind parameter, indicating whether to bind the current thread to the acquired cpu lock. If the bind parameter=true, then the current The thread will run on the CPU obtained in acquireLock. If the bind parameter=false, it means that acquireLock will be bound at some time in the future.

We mentioned AffinityStrategy above. This AffinityStrategy can be used as a parameter of acquireLock:

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

By calling the acquireLock method of the current AffinityLock, the current thread can be assigned an AffinityLock related to the previous lock strategy. .

AffinityLock also provides a dumpLocks method to view the current binding status of the CPU and thread. Let's take an example:

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() {
                @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);
Copy after login

In the above code, we created a thread pool of 4 threads, the corresponding ThreadFactory is AffinityThreadFactory, named the thread pool bg, and allocated 3 AffinityStrategy. This means first allocating to the same core, then to a different socket, and finally to any available CPU.

During the specific execution process, we submitted 12 threads, but our Thread pool only has a maximum of 4 threads. It is foreseeable that only 4 threads in the results returned by the AffinityLock.dumpLocks method will be bound to the CPU. , let’s take a look:

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
Copy after login

As you can see from the output, CPU0 is unavailable. The other 7 CPUs are available, but only have 4 threads bound to them, which matches our previous analysis.

Next, we modify the AffinityStrategy of AffinityThreadFactory as follows:

new AffinityThreadFactory("bg", SAME_CORE)
Copy after login

means that the thread will only be bound to the same core, because in the current hardware, one core can It can only support the binding of one thread, so it can be predicted that the final result will only be bound to one thread. The running results are as follows:

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);
    }
Copy after login

实时上这种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);
    }
Copy after login

再看下setAffinity的使用:

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

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

The above is the detailed content of How to bind thread to specific CPU in Java?. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:yisu.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!