2

在以下状态下是否会发生错误共享:

Class Foo{

   int x;
   int y;

}

两个线程同时修改 x 和 y?还是无法判断编译器可能会将 x 和 y 优化为寄存器?

4

3 回答 3

1

当然它可能会发生(可能是这里的关键字),你不能确定这两个变量是否会明显地出现在同一个缓存行上。编译器不会做任何事情(至少javac)来防止这样的情况,例如让这些变量保存在不同的缓存行上可能会非常昂贵,并且需要大量实际需要的证据。

是的,您的评论是正确的,缓存失效会经常发生,并且可能是造成瓶颈的原因。但是测量这并不容易,你可以在这里看到一个例子。

请注意,由于 jdk-8 存在@Contended将填充条目以恰好适合缓存行。

于 2017-11-30T08:17:35.347 回答
0

像这样的测试用例:

public class FalseSharing implements Runnable {
public final static int NUM_THREADS = 2; // change

public final static long ITERATIONS = 50L * 1000L * 1000L;
private static VolatileLong[] longs = new VolatileLong[NUM_THREADS];

static {
    for (int i = 0; i < longs.length; i++) {
        longs[i] = new VolatileLong();
    }
}

private final int arrayIndex;

public FalseSharing(final int arrayIndex) {
    this.arrayIndex = arrayIndex;
}

public static void main(final String[] args) throws Exception {
    final long start = System.currentTimeMillis();
    runTest();
    System.out.println("duration = " + (System.currentTimeMillis() - start));
}

private static void runTest() throws InterruptedException {
    Thread[] threads = new Thread[NUM_THREADS];
    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();
    }
}

public void run() {
    long i = ITERATIONS + 1;
    while (0 != --i) {
        longs[arrayIndex].value = i;
    }
}

public final static class VolatileLong {
    public long p1, p2, p3, p4, p5, p6, p7; // padding
    public long value = 0L; // change to volatile when test
    public long p1_1, p2_1, p3_1, p4_1, p5_1, p6_1, p7_1; // padding
}}

测试结果(5 次)(在 Intel Core i5 2 核中运行):

  • 无填充的易失性(毫秒) 1360 1401 1684 1323 1383
  • 带填充的易失性(毫秒) 568 612 653 638 669
  • 非易失性无填充(ms) 41 35 40 35 44
  • 带填充的非易失性(毫秒) 38 39 44 49 51

所以在我看来,非易失性字段不会发生虚假共享

于 2018-05-23T15:48:20.543 回答
0

我的测试证明和你的一样。

我也在使用 com.lmax.disruptor.Sequence 进行测试。

non-volatile long > volatile long 使用 lasset(Sequence.set) > Sequence.setVolatile == volatile long with padding > volatile long without padding

于 2021-04-16T13:48:17.480 回答