伪填充问题

发生场景

多核 cpu 下多个线程之间改写连续不同资源。

发生机制

因为 cpu 往往使用高速缓冲来加快对变量的读取，而 mesi 协议会导致不同 cpu 上的线程修改对应的高速缓存时，会使其它 cpu 上的相应的高速缓存行失效（如果存在），那么另一个 cpu 修改该高速缓冲行中的变量时（即使不是同一个变量）就会从内存中进行读取，这样又会导致原来 cpu 的对应缓冲行失效，如此反复，导致 cpu 对于变量的修改读取都需要经过内存而无法有效利用高速缓冲，从而减慢速度。

代码实现

发生伪填充

Copy
public final class FalseSharing
implements Runnable
{
public final static int NUM_THREADS = 2; // change
public final static long ITERATIONS = 500 * 1000 * 1000;
private final int arrayIndex;

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

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

public static void main(final String[] args) throws Exception
{
final long start = System.nanoTime();
runTest();
System.out.println("duration = " + (System.nanoTime() - 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 volatile long value = 0;
}
}

未发生伪填充

Copy
public final class FalseSharing
implements Runnable
{
public final static int NUM_THREADS = 2; // change
public final static long ITERATIONS = 500 * 1000 * 1000;
private final int arrayIndex;

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

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

public static void main(final String[] args) throws Exception
{
final long start = System.nanoTime();
runTest();
System.out.println("duration = " + (System.nanoTime() - 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;
}
}

@sun.misc.Contended
public final static class VolatileLong
{
public volatile long value = 0;
}
}

其中需要加入 jvm 参数 - XX:-RestrictContended 。

实验结果

发生伪填充

未发生伪填充