Scenario
Rewriting different resources between multiple threads on a multi-core CPU.
Mechanism
Because CPUs often use caches to speed up variable reading, the MESI protocol can cause the corresponding cache lines on different CPUs to become invalid when threads on different CPUs modify their corresponding caches. When another CPU modifies a variable in that cache line (even if it is not the same variable), it will read from memory, causing the corresponding cache line of the original CPU to become invalid. This process repeats, causing the CPU to need to go through memory for every modification and reading of variables, unable to effectively utilize the cache, thereby slowing down the speed.
Code Implementation
- False Sharing Occurs
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;
}
}
- False Sharing Does Not Occur
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;
}
}
The JVM parameter -XX:-RestrictContended needs to be added.
Experimental Results
- False Sharing Occurs
- False Sharing Does Not Occur