原文:False Shareing && Java 7 (依然是马丁的博客) 译者:杨帆 校对:方腾飞
在我前一篇有关伪共享的博文中,我提到了可以加入闲置的long字段来填充缓存行来避免伪共享。但是看起来Java 7变得更加智慧了,它淘汰或者是重新排列了无用的字段,这样我们之前的办法在Java 7下就不奏效了,但是伪共享依然会发生。我在不同的平台上实验了一些列不同的方案,并且最终发现下面的代码是最可靠的。(译者注:下面的是最终版本,马丁在大家的帮助下修改了几次代码)
01 |
import java.util.concurrent.atomic.AtomicLong;
|
03 |
public final class FalseSharing
|
06 |
public final static int NUM_THREADS = 4 ;
|
07 |
public final static long ITERATIONS = 500L * 1000L * 1000L;
|
08 |
private final int arrayIndex;
|
10 |
private static PaddedAtomicLong[] longs = new PaddedAtomicLong[NUM_THREADS];
|
13 |
for ( int i = 0 ; i < longs.length; i++)
|
15 |
longs[i] = new PaddedAtomicLong();
|
19 |
public FalseSharing( final int arrayIndex)
|
21 |
this .arrayIndex = arrayIndex;
|
24 |
public static void main( final String[] args) throws Exception
|
26 |
final long start = System.nanoTime();
|
28 |
System.out.println( "duration = " + (System.nanoTime() - start));
|
31 |
private static void runTest() throws InterruptedException
|
33 |
Thread[] threads = new Thread[NUM_THREADS];
|
35 |
for ( int i = 0 ; i < threads.length; i++)
|
37 |
threads[i] = new Thread( new FalseSharing(i));
|
40 |
for (Thread t : threads)
|
45 |
for (Thread t : threads)
|
53 |
long i = ITERATIONS + 1 ;
|
56 |
longs[arrayIndex].set(i);
|
61 |
public static long sumPaddingToPreventOptimisation( final int index)
|
63 |
PaddedAtomicLong v = longs[index];
|
64 |
return v.p1 + v.p2 + v.p3 + v.p4 + v.p5 + v.p6;
|
67 |
public static class PaddedAtomicLong extends AtomicLong
|
69 |
public volatile long p1, p2, p3, p4, p5, p6 = 7L;
|
用以上这种办法我获得了和上一篇博客里提到的相近的性能,读者可以把PaddedAtomicLong里面那行填充物注释掉再跑测试看看效果。
我想我们大家都有权去跟Oracle投诉,让他们在JDK里默认加入缓存行对齐的函数或者是被填充好的原子类型,这和其他一些底层改变会让Java成为一门真真正正的并发编程语言。我们一直以来不断的在听到他们讲多核时代正在到来,但是我要说的是在这方面Java需要快点赶上来。