为什么volatile比非易失性更快?

时间:2014-02-06 09:20:54

标签: java performance microbenchmark

阅读问题Why is processing a sorted array faster than an unsorted array?后 我们曾尝试将变量设置为volatile(我预计,当我使用volatile时,它必须工作得更慢,但它的工作速度更快) 这是我的代码没有不稳定:(它工作大约11秒。)

import java.util.Arrays;
import java.util.Random;

public class GGGG {

public static void main(String[] args) {
    int arraySize = 32768;
    int data[];
    data = new int[arraySize];

    Random rnd = new Random(0);
    for (int c = 0; c < arraySize; ++c) {
        data[c] = rnd.nextInt() % 256;
    }

    Arrays.sort(data);

    long start = System.nanoTime();
    long sum = 0;

    for (int i = 0; i < 200000; ++i) {
        for (int c = 0; c < arraySize; ++c) {
            if (data[c] >= 128) {
                sum += data[c];
            }
        }
    }

    System.out.println((System.nanoTime() - start) / 1000000000.0);
    System.out.println("sum = " + sum);

    System.out.println("=========================");
}

输出是:

10.876173341
sum = 310368400000
=========================



这是当我使用arraySize和数据变量作为volatile时,它工作大约7秒:

import java.util.Arrays;
import java.util.Random;

public class GGGG {

static volatile int arraySize = 32768;
static volatile int data[];

public static void main(String[] args) {
    data = new int[arraySize];

    Random rnd = new Random(0);
    for (int c = 0; c < arraySize; ++c) {
        data[c] = rnd.nextInt() % 256;
    }

    Arrays.sort(data);

    long start = System.nanoTime();
    long sum = 0;

    for (int i = 0; i < 200000; ++i) {
        for (int c = 0; c < arraySize; ++c) {
            if (data[c] >= 128) {
                sum += data[c];
            }
        }
    }

    System.out.println((System.nanoTime() - start) / 1000000000.0);
    System.out.println("sum = " + sum);

    System.out.println("=========================");
}

使用volatile输出:

6.776267265
sum = 310368400000
=========================

所有我都期望用volatile来减缓这个过程,但它的工作速度更快。发生了什么事?

1 个答案:

答案 0 :(得分:8)

我将仅列出您的代码的两个主要问题:

  1. 没有热身;
  2. 一切都发生在main方法中,因此JIT编译的代码只能通过堆栈替换来运行。
  3. 使用jmh工具重做案例,​​我得到的时间与预期的一样。

    @OutputTimeUnit(TimeUnit.MICROSECONDS)
    @BenchmarkMode(Mode.AverageTime)
    @Warmup(iterations = 3, time = 2)
    @Measurement(iterations = 5, time = 3)
    @State(Scope.Thread)
    @Threads(1)
    @Fork(2)
    public class Writing
    {
      static final int ARRAY_SIZE = 32768;
    
      int data[] = new int[ARRAY_SIZE];
      volatile int volatileData[] = new int[ARRAY_SIZE];
    
      @Setup public void setup() {
        Random rnd = new Random(0);
        for (int c = 0; c < ARRAY_SIZE; ++c) {
          data[c] = rnd.nextInt() % 256;
          volatileData[c] = rnd.nextInt() % 256;
        }
        Arrays.sort(data);
        System.arraycopy(data, 0, volatileData, 0, ARRAY_SIZE);
      }
    
      @GenerateMicroBenchmark
      public long sum() {
        long sum = 0;
        for (int c = 0; c < ARRAY_SIZE; ++c) if (data[c] >= 128) sum += data[c];
        return sum;
      }
    
      @GenerateMicroBenchmark
      public long volatileSum() {
        long sum = 0;
        for (int c = 0; c < ARRAY_SIZE; ++c) if (volatileData[c] >= 128) sum += volatileData[c];
        return sum;
      }
    }
    

    结果如下:

    Benchmark       Mode   Samples         Mean   Mean error    Units
    sum             avgt        10       21.956        0.221    us/op
    volatileSum     avgt        10       40.561        0.264    us/op