Java中volatile副作用:不使用CPU缓存


高速缓存位于在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