zzh

zzh

假填充問題

發生場景

多核 cpu 下多個線程之間改寫連續不同資源。

發生機制

因為 cpu 往往使用高速緩衝來加快對變量的讀取,而 mesi 協議會導致不同 cpu 上的線程修改對應的高速緩存時,會使其它 cpu 上的相應的高速緩存行失效(如果存在),那麼另一個 cpu 修改該高速緩衝行中的變量時(即使不是同一個變量)就會從內存中進行讀取,這樣又會導致原來 cpu 的對應緩衝行失效,如此反復,導致 cpu 對於變量的修改讀取都需要經過內存而無法有效利用高速緩衝,從而減慢速度。

代碼實現
  • 發生偽填充
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;
    }
}
  • 未發生偽填充
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 。

實驗結果
  • 發生偽填充

image

  • 未發生偽填充

image

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。