当前位置: 首页 > 面试题库 >

为什么访问volatile变量比成员慢100左右?

曹光霁
2023-03-14
问题内容

在这里,我编写了有关本地,成员,易失成员的访问速度的测试:

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)上的结果:

回合:1 空:5本地:10成员:312 VM会员:33378

回合:2 空:31本地:0成员:294 VM会员:33180

回合:3 空:0本地:0成员:306 VM会员:33085

回合:4 空:0本地:0成员:300 VM会员:33066

回合:5 空:0本地:0成员:303 VMember:33078

回合:6 空:0本地:0成员:299 VMember:33398

回合:7 空:0本地:0成员:305 VMember:33139

回合:8 空:0本地:0成员:307 VM会员:33490

回合:9 空:0本地:0成员:350 VM会员:35291

回合:10 空:0本地:0成员:332 VM会员:33838

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

PS:我还在Core II CPU机器上进行了测试。它大约是9:50,大约慢5倍。似乎这也与CPU架构有关。5倍还大吧?


问题答案:

接取volatile防止一些JIT
optimisaton。如果您的循环实际上并没有执行任何操作,那么这尤其重要,因为JIT可以优化此类循环(除非您具有可变字段)。如果将循环“长时间”运行,则损耗会增加更多。

在更实际的测试中,您可能希望volatile将Cirical代码的速度降低30%到10倍。在大多数实际程序中,这几乎没有什么区别,因为CPU足够智能,可以“意识到”只有一个内核在使用易失性字段并对其进行缓存,而不是使用主内存。



 类似资料:
  • 我假设在每次调用时都必须检查其变量是否初始化,因此将比慢,这样做对吗?

  • 问题内容: 如果在一个类中我有一个ConcurrentHashMap实例,该实例将被多个线程修改并读取,则可以这样定义: 添加到myMap字段会导致错误,提示我只能使用final或volatile。为什么不能两者兼而有之? 问题答案: 仅与变量本身的修改有关,与变量所指的对象无关。有一个字段是没有意义的,因为不能修改最终字段。只需声明该字段,就可以了。

  • 我有一个表,其中有(其他20个)列、和,以及和的索引。该表有大约500k行。 为什么以下to查询在速度上差异如此之大?查询A需要0.3秒,而查询B需要28秒。 查询A 我使用MySQL5.1.34。

  • 通过下列任意一个方法访问成员变量时将返回 Field 类型的对象或数组。 getFields() getField(String name) getDeclaredFields() getDeclaredField(String name) 上述方法返回的 Field 对象代表一个成员变量。例如,要访问一个名称为 price 的成员变量,示例代码如下: Field 类的常用方法如表 1 所示 表1

  • 最近在review代码的时候发现,使用了空指针调用成员函数,并且成员函数内部有使用到成员变量,居然没有出错。很是奇怪,就用一篇博客把关于空指针调用成员函数相关的内容总结起来。 空指针调用成员函数 调用普通成员函数 如果空指针调用普通成员函数,看该函数体中是否使用到了this指针(是否访问非静态成员变量)。如果使用到了this指针,程序会崩溃;如果没有使用到this指针,程序不会崩溃。当然,如果访问

  • 来自Javadocs 使用易失性变量降低了内存一致性错误的风险,因为对易失性变量的任何写入都与同一变量的后续读取建立了先发生后发生的关系。这意味着对易失性变量的更改始终对其他线程可见。 如果对volatile变量所做的更改对任何其他线程都是可见的,那么为什么在多个线程写入该变量的情况下不能使用volatile变量呢。为什么volatile只用于一个线程正在写入或读取该变量,而另一个线程只读取该变量