教育行業(yè)A股IPO第一股(股票代碼 003032)

全國咨詢/投訴熱線:400-618-4000

什么是多線程環(huán)境下的偽共享(false sharing)?

更新時間:2023年07月17日10時11分 來源:傳智教育 瀏覽次數(shù):

好口碑IT培訓(xùn)

  在Java中,偽共享(false sharing)是指多線程環(huán)境下,由于緩存一致性協(xié)議的影響,不同線程訪問同一緩存行中的不同數(shù)據(jù)造成的性能下降現(xiàn)象。當(dāng)多個線程同時訪問不同變量,但這些變量存儲在同一緩存行中時,每個線程只修改自己的變量,但由于緩存一致性協(xié)議的要求,需要將整個緩存行的數(shù)據(jù)進(jìn)行更新,導(dǎo)致其他線程緩存的數(shù)據(jù)失效,從而影響了性能。

  接下里筆者用一段簡單的Java代碼,來演示下偽共享的效果:

public class FalseSharingDemo implements Runnable {
    private static final int NUM_THREADS = 2;
    private static final long ITERATIONS = 500000000L;
    private static final int ARRAY_SIZE = 8;

    private static VolatileLong[] longs = new VolatileLong[ARRAY_SIZE];

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

    private final int arrayIndex;

    public FalseSharingDemo(int arrayIndex) {
        this.arrayIndex = arrayIndex;
    }

    public static void main(String[] args) throws InterruptedException {
        Thread[] threads = new Thread[NUM_THREADS];

        for (int i = 0; i < NUM_THREADS; i++) {
            threads[i] = new Thread(new FalseSharingDemo(i));
        }

        for (Thread t : threads) {
            t.start();
        }

        for (Thread t : threads) {
            t.join();
        }
    }

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

    public static class VolatileLong {
        public volatile long value = 0L;
    }
}

  在上面的示例代碼中,我們創(chuàng)建了一個包含多個VolatileLong對象的數(shù)組。每個VolatileLong對象都包含一個volatile修飾的long類型的變量。在run()方法中,每個線程都會通過循環(huán)將自己的索引對應(yīng)的VolatileLong對象的value字段設(shè)置為遞減的值。

  當(dāng)我們運(yùn)行該示例代碼時,由于VolatileLong對象存儲在同一緩存行中,不同線程對不同的VolatileLong對象進(jìn)行操作,但由于緩存一致性協(xié)議的要求,每次寫操作都會導(dǎo)致整個緩存行的數(shù)據(jù)失效。這將引起多個線程之間頻繁的緩存行無效和更新,導(dǎo)致性能下降。

  為了解決偽共享問題,可以使用填充(padding)技術(shù)來確保不同變量在不同的緩存行中,從而避免了不必要的緩存行無效和更新。可以通過在VolatileLong類中增加填充字段來解決偽共享問題,例如:

public static class VolatileLong {
    public volatile long value = 0L;
    public long padding1, padding2, padding3, padding4, padding5, padding6;
}

  通過在VolatileLong類中添加填充字段,可以將不同的VolatileLong對象分散到不同的緩存行中,從而避免了偽共享帶來的性能下降。

0 分享到:
和我們在線交談!