高并发下的魔术-缓存行填充
缓存系统中缓存通常是以缓存行为单位存储。常见缓存行通常为64字节。所以一个缓存行中通常会存放几个变量,如果这几个独立变量被多线程修改时,会因为共享同一个缓存行而影响彼此的性能。如果能将独立变量填充满整个缓存行,那么多线程之间就不再是共享关系,而是各自占用多个缓存行,进而提高性能。这也就是缓存填充能提高多线程的关键理论所在。那么,真实情况是否确实如此呢,我们可以做个有趣的实验。一组让多个线程修改一个long类型数组,另一组是修改填充后的VolatileLong对象数组。然后比对各自所需要的时间。
public class FalseSharing implements Runnable {
public static final int THREAD_NUM = 4;
public final static long ITERATIONS = 500 * 1000 * 1000L;
private int arrayIdx;
private static VolatileLong[] longs = new VolatileLong[THREAD_NUM];
static {
for (int i = 0; i < longs.length; i++) {
longs[i] = new VolatileLong();
}
}
public FalseSharing(int arrayIdx) {
this.arrayIdx = arrayIdx;
}
private static void runTest() throws InterruptedException {
Thread[] threads = new Thread[THREAD_NUM];
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(new FalseSharing(i));
}
for (Thread t : threads) {
t.start();
}
for (Thread t : threads) {
t.join();
}
}
@Override
public void run() {
long i = ITERATIONS + 1;
while (0 != --i) {
longs[arrayIdx].value = i;
// longs[arrayIdx].value++;
}
}
public static void main(String[] args) throws InterruptedException {
long startTime = System.currentTimeMillis();
runTest();
long endTime = System.currentTimeMillis();
System.out.println("duration = " + (endTime - startTime));
}
public final static class VolatileLong {
public volatile long value = 0L;
public long p1, p2, p3, p4, p5, p6; // comment out
}
}
机器参数为双核intel core i5。通过调节线程数,每次调节运行5次取平均数。统计出花费的时间。得出的数据如下:

从图中可见确实缓存填充会带来性能上的提升,尤其是随着线程数的增长,性能提升的效果就越明显。
参考:
1、http://ifeve.com/falsesharing/
2、《Java 并发编程的艺术》
3、《Java 并发编程实战》

浙公网安备 33010602011771号