7

这里我写了一个关于local、member、volatile成员访问速度的测试:

public class VolatileTest {

public int member = -100;

public volatile int volatileMember = -100;

public static void main(String[] args) {
    int testloop = 10;
    for (int i = 1; i <= testloop; i++) {
        System.out.println("Round:" + i);
        VolatileTest vt = new VolatileTest();
        vt.runTest();
        System.out.println();
    }
}

public void runTest() {
    int local = -100;

    int loop = 1;
    int loop2 = Integer.MAX_VALUE;
    long startTime;

    startTime = System.currentTimeMillis();
    for (int i = 0; i < loop; i++) {
        for (int j = 0; j < loop2; j++) {
        }
        for (int j = 0; j < loop2; j++) {
        }
    }
    System.out.println("Empty:" + (System.currentTimeMillis() - startTime));

    startTime = System.currentTimeMillis();
    for (int i = 0; i < loop; i++) {
        for (int j = 0; j < loop2; j++) {
            local++;
        }
        for (int j = 0; j < loop2; j++) {
            local--;
        }
    }
    System.out.println("Local:" + (System.currentTimeMillis() - startTime));

    startTime = System.currentTimeMillis();
    for (int i = 0; i < loop; i++) {
        for (int j = 0; j < loop2; j++) {
            member++;
        }
        for (int j = 0; j < loop2; j++) {
            member--;
        }
    }
    System.out.println("Member:" + (System.currentTimeMillis() - startTime));

    startTime = System.currentTimeMillis();
    for (int i = 0; i < loop; i++) {
        for (int j = 0; j < loop2; j++) {
            volatileMember++;
        }
        for (int j = 0; j < loop2; j++) {
            volatileMember--;
        }
    }
    System.out.println("VMember:" + (System.currentTimeMillis() - startTime));

}
}

这是我的 X220 (I5 CPU) 上的结果:

Round:1 Empty:5 Local:10 Member:312 VMember:33378

Round:2 Empty:31 Local:0 Member:294 VMember:33180

Round:3 Empty:0 Local:0 Member:306 VMember:33085

Round:4 Empty:0 Local:0 Member:300 VMember:33066

Round:5 Empty:0 Local:0 Member:303 VMember:33078

Round:6 Empty:0 Local:0 Member:299 VMember:33398

Round:7 Empty:0 Local:0 Member:305 VMember:33139

Round:8 Empty:0 Local:0 Member:307 VMember:33490

Round:9 Empty:0 Local:0 Member:350 VMember:35291

Round:10 Empty:0 Local:0 Member:332 VMember:33838

令我惊讶的是,访问 volatile 成员的速度比普通成员慢 100 倍。我知道 volatile 成员有一些突出特性,例如对它的修改将立即对所有线程可见,对 volatile 变量的访问点起着“内存屏障”的作用。但是所有这些副作用会是100倍慢的主要原因吗?

PS:我也在Core II CPU机器上做了测试。大约是 9 点 50 分,慢了大约 5 倍。似乎这也与CPU拱门有关。5倍还是很大的吧?

4

4 回答 4

8

volatile 成员永远不会被缓存,因此它们是直接从主内存中读取的。

于 2012-06-21T06:52:20.977 回答
4

访问volatile变量会阻止 CPU 在访问前后重新排序指令,这通常会减慢执行速度。

于 2012-06-21T05:42:21.093 回答
4

访问以volatile防止某些 JIT 优化。如果您有一个实际上不做任何事情的循环,这一点尤其重要,因为 JIT 可以优化此类循环(除非您有一个 volatile 字段)如果您“长时间”运行循环,则差异应该增加更多。

在更实际的测试中,您可能会期望volatile对关键代码慢 30% 到 10 倍。在大多数实际程序中,它几乎没有什么区别,因为 CPU 足够聪明,可以“意识到”只有一个内核在使用 volatile 字段并将其缓存而不是使用主存储器。

于 2012-06-21T07:08:38.923 回答
0

使用 volatile 会直接从内存中读取,这样每个 cpu 核心都会在下一次 get 时从变量中获取变化,没有使用 cpu 缓存,不会使用寄存器,L1~L3 缓存技术,从

  1. 寄存器 1 个时钟周期
  2. L1 高速缓存 4 个时钟周期
  3. L2 高速缓存 11 个时钟周期
  4. 三级缓存 30~40 个时钟周期
  5. 内存 100+ 个时钟周期

这就是为什么使用 volatile 时结果会慢 100 倍的原因。

于 2020-04-02T07:21:01.010 回答