Java 7与伪共享的新仇旧恨

原文:False Shareing && Java 7 (依然是马丁的博客)  译者:杨帆 校对:方腾飞

在我前一篇有关伪共享的博文中,我提到了可以加入闲置的long字段来填充缓存行来避免伪共享。但是看起来Java 7变得更加智慧了,它淘汰或者是重新排列了无用的字段,这样我们之前的办法在Java 7下就不奏效了,但是伪共享依然会发生。我在不同的平台上实验了一些列不同的方案,并且最终发现下面的代码是最可靠的。(译者注:下面的是最终版本,马丁在大家的帮助下修改了几次代码)

01 import java.util.concurrent.atomic.AtomicLong;
02  
03 public final class FalseSharing
04     implements Runnable
05 {
06     public final static int NUM_THREADS = 4; // change
07     public final static long ITERATIONS = 500L * 1000L * 1000L;
08     private final int arrayIndex;
09  
10     private static PaddedAtomicLong[] longs = new PaddedAtomicLong[NUM_THREADS];
11     static
12     {
13         for (int i = 0; i < longs.length; i++)
14         {
15             longs[i] = new PaddedAtomicLong();
16         }
17     }
18  
19     public FalseSharing(final int arrayIndex)
20     {
21         this.arrayIndex = arrayIndex;
22     }
23  
24     public static void main(final String[] args) throws Exception
25     {
26         final long start = System.nanoTime();
27         runTest();
28         System.out.println("duration = " + (System.nanoTime() - start));
29     }
30  
31     private static void runTest() throws InterruptedException
32     {
33         Thread[] threads = new Thread[NUM_THREADS];
34  
35         for (int i = 0; i < threads.length; i++)
36         {
37             threads[i] = new Thread(new FalseSharing(i));
38         }
39  
40         for (Thread t : threads)
41         {
42             t.start();
43         }
44  
45         for (Thread t : threads)
46         {
47             t.join();
48         }
49     }
50  
51     public void run()
52     {
53         long i = ITERATIONS + 1;
54         while (0 != --i)
55         {
56             longs[arrayIndex].set(i);
57         }
58     }
59  
60     // 这段代码的来历可以看4楼的回复
61     public static long sumPaddingToPreventOptimisation(final int index)
62     {
63         PaddedAtomicLong v = longs[index];
64         return v.p1 + v.p2 + v.p3 + v.p4 + v.p5 + v.p6;
65     }
66  
67     public static class PaddedAtomicLong extends AtomicLong
68     {
69         public volatile long p1, p2, p3, p4, p5, p6 = 7L;
70     }
71 }

用以上这种办法我获得了和上一篇博客里提到的相近的性能,读者可以把PaddedAtomicLong里面那行填充物注释掉再跑测试看看效果。

我想我们大家都有权去跟Oracle投诉,让他们在JDK里默认加入缓存行对齐的函数或者是被填充好的原子类型,这和其他一些底层改变会让Java成为一门真真正正的并发编程语言。我们一直以来不断的在听到他们讲多核时代正在到来,但是我要说的是在这方面Java需要快点赶上来。

上一篇:Windows 10秋季创作者更新:桌面端也可享受滑动输入


下一篇:三星宣布年底关闭天津工厂