Java中volatile副作用:不使用CPU快取

banq發表於2021-04-02

快取記憶體位於在CPU和主記憶體之間,是一個速度更快的記憶體模組,其總體目的是提升效能。
快取通常是由具有不同大小和訪問時間的幾個層次級別組成。L1快取是最小和最快的。L2更大而更慢。L3更大甚至更慢-但仍然比主記憶體快得多。用於特定資料結構的資料量越少,將其放入快取記憶體的機會就越大,從而可以顯著提高效能。
volatile關鍵字之所以特殊,是因為volatile關鍵字不快取變數的值,並且始終從主記憶體中讀取變數。這意味著它不使用CPU快取,因為它是為了執行緒安全。
 
原文點選標題,測試案例:

@State(Scope.Thread)
public class JMHArrayBenchmarking {
    
    private static final int ARRAY_SIZE = 64 * 1024 * 1024;
    public Integer[] array;
    public volatile Integer[] vArray;
    @Setup
    public void setup() {
        array = new Integer[ARRAY_SIZE];
        vArray = new Integer[ARRAY_SIZE];
        Arrays.fill(array, 1);
        Arrays.fill(vArray, 1);
    }
    
    @TearDown
    public void cleanup() {
        array = new Integer[ARRAY_SIZE];
        vArray = new Integer[ARRAY_SIZE];
    }
    
    @Benchmark
    @BenchmarkMode(Mode.SingleShotTime)
    public void doMultiply() {
        for (int i = 0; i < array.length; i++) {
            array[i] = array[i] * 3;
        }
    }
    
    @Benchmark
    @BenchmarkMode(Mode.SingleShotTime)
    public void doVolatileMultiply() {
        for (int i = 0; i < vArray.length; i++) {
            vArray[i] = vArray[i] * 3;
        }
    }


}

在上面的示例中,說明了doMultiply()將元素插入到普通陣列中的方法以及doVolatileMultiply()將元素插入到volatile陣列中的方法。透過比較兩種方法的速度,我們可以看到該doVolatileMultiply()方法的執行速度比該doMultiply()方法慢,因為volatile關鍵字不使用CPU快取來儲存元素。它直接從主記憶體中獲取元素,這是為了執行緒安全。
結果:

Benchmark                         Mode   Score     Units
JMHArrayBenchmarking.doMultiply          ss     0.529     s/op
JMHArrayBenchmarking.doVolatileMultiply     ss    0.570      s/op


 

相關文章