可以使用以下状态进行错误共享:
Class Foo{
int x;
int y;
}
两个线程同时修改x和y?或者是否无法判断编译器是否可以优化x和y到寄存器?
答案 0 :(得分:1)
当然它可能会发生(可能是这里的关键字),你无法确定这两个变量是否会在同一个缓存行上最终结束。编译器不会做任何事情(至少javac
)来防止将这些变量保存在不同的缓存行上的情况可能非常昂贵,并且需要大量实际需要的证据。
是的,你的评论是正确的,缓存失效会经常发生,可能成为瓶颈的原因。但是测量这个并不容易,你可以看到一个例子here。
请注意,由于jdk-8有@Contended
,它会填充条目以恰好适合缓存行。
答案 1 :(得分: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次)(在2核的Intel Core i5中运行):
因此,在我看来,非易失性字段不会发生虚假共享
答案 2 :(得分:0)
我的测试证明和你的一样。
我也在使用 com.lmax.disruptor.Sequence 进行测试。
non-volatile long > volatile long use lasyset(Sequence.set) > Sequence.setVolatile == volatile long with padding > volatile long without padding