java - 为什么 volatile 比非 volatile 工作得更快?

标签 java performance microbenchmark

阅读问题后Why is processing a sorted array faster than an unsorted array? 我们曾尝试将变量设置为 volatile (我预计,当我使用 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
=========================

我本以为 volatility 会减慢进程,但它运行得更快。发生什么事了?

最佳答案

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

  1. 没有预热;
  2. 一切都发生在 main 方法中,因此 JIT 编译的代码只能通过栈上替换来运行。

使用 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

关于java - 为什么 volatile 比非 volatile 工作得更快?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21598558/

相关文章:

java - 如何创建一个方法来测量执行一个方法所花费的时间

java - 如何用 Java 编写正确的微基准测试?

java - 计算文件中相同的行数,JAVA

sql - Oracle 不能推断这些查询是相同的——生成了非常不同的执行计划

c# - OnMouseMove 不会在 WPF 中的 Canvas 上触发

performance - 为什么 cachegrind 忽略了 L3 缓存,这与文档相矛盾?

java - JMH 基准迭代中的随机峰

java - 将二叉树展平为链表

java - 为一个奇怪的程序创建一个测试类

java - 如何在 GAE 部署中包含外部类?