我曾经听说过线程亲和性和线程亲和性执行器。但至少在Java中,我找不到合适的参考资料。有人能否解释一下这是什么意思?
我曾经听说过线程亲和性和线程亲和性执行器。但至少在Java中,我找不到合适的参考资料。有人能否解释一下这是什么意思?
有两个问题。首先,最好让线程亲和一个特定的CPU(核心),以充分利用其CPU本地缓存。这必须由操作系统处理。这种线程的CPU亲和性通常也称为“线程亲和性”。在Java的情况下,没有标准API来控制这一点。但是,正如其他答案所提到的,有第三方库。
其次,在Java中观察到,在典型程序中对象是线程相关的,即大多数情况下仅由一个线程使用。因此,JVM的优化器的任务是确保将亲和于一个线程的对象放置在内存中彼此靠近,以适应一个CPU的缓存,但不要将亲和于不同线程的对象放置得太靠近,以避免它们共享缓存行,否则两个CPU / Core必须过于频繁地进行同步。
理想情况是一个CPU可以独立地处理一些对象,而另一个CPU可以处理放置在不相关内存区域中的其他对象。
考虑Java对象的线程亲和性的实际优化示例包括:
使用TLABs,每个对象都在专门为创建它的线程分配的内存区域中开始其生命周期。根据生成垃圾收集器背后的主要假设(“大多数对象年轻时就会死亡”),大多数对象将在这样的线程本地缓冲区中度过它们的整个生命周期。
使用偏向锁定,JVM将使用乐观的假设执行锁定操作,即对象仅由同一线程锁定,仅在此假设不成立时切换到更昂贵的锁定实现。
为了解决另一端,即已知由多个线程访问的字段,HotSpot / OpenJDK具有一个注释(当前不是公共API的一部分),用于标记它们,以指示JVM将这些数据移开,远离其他潜在未共享的数据。
Java Thread Affinity version 1.4库旨在兼顾两者优点,让您为关键线程保留逻辑线程,并为性能最敏感的线程保留整个核心。不太关键的线程仍将享受超线程的好处。例如以下代码片段:
AffinityLock al = AffinityLock.acquireLock();
try {
// find a cpu on a different socket, otherwise a different core.
AffinityLock readerLock = al.acquireLock(DIFFERENT_SOCKET, DIFFERENT_CORE);
new Thread(new SleepRunnable(readerLock, false), "reader").start();
// find a cpu on the same core, or the same socket, or any free cpu.
AffinityLock writerLock = readerLock.acquireLock(SAME_CORE, SAME_SOCKET, ANY);
new Thread(new SleepRunnable(writerLock, false), "writer").start();
Thread.sleep(200);
} finally {
al.release();
}
// allocate a whole core to the engine so it doesn't have to compete for resources.
al = AffinityLock.acquireCore(false);
new Thread(new SleepRunnable(al, true), "engine").start();
Thread.sleep(200);
System.out.println("\nThe assignment of CPUs is\n" + AffinityLock.dumpLocks());