【问题标题】:Why volatile is working faster than non-volatile?为什么 volatile 比 non-volatile 工作得更快?
【发布时间】:2014-03-03 03:24:14
【问题描述】:

看完问题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
=========================

我原本期望 volatile 会减慢这个过程,但它的工作速度更快。发生了什么事?

【问题讨论】:

  • 只有static 变量我得到4.5 作为输出时间,static volatile 我得到11.7。此外,如果我将变量设置为既不是 static 也不是 volatile 而是将它们放入方法中,它是 4.6
  • 您将变量声明为 static 字段,并声明为方法 main 的局部变量。将大数组声明为方法的局部变量可能意味着开销,这可以解释为什么 volatile 在您的情况下会更快。两次都与静态变量进行比较。
  • 我刚刚用静态(没有易失性)检查了它,它给了我 8 秒。而且,当我在方法内部或外部声明(即使是静态的)时有什么区别 - 我所做的只是计算逻辑的时间:)

标签: java performance microbenchmark


【解决方案1】:

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

  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

【讨论】:

    猜你喜欢
    • 2012-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-20
    • 2012-07-02
    • 2019-06-10
    相关资源
    最近更新 更多