【问题标题】:Can volatile be eliminated by Java compiler optimizationsJava编译器优化可以消除volatile
【发布时间】:2020-01-08 00:41:09
【问题描述】:

Java 编译器(版本 5 或更高版本)执行的优化可以删除变量的“volatile”声明吗?

更准确地说,在以下任何一种情况下,一个易失性变量是否可以变成一个非易失性变量:

  • 如果没有多线程,即如果应用程序从不使用多个线程?

  • 如果一个 volatile 变量由一个线程写入但从未被任何其他线程访问过?

  • 如果一个 volatile 变量被多个线程读取但从未修改(只读,无写入)?

【问题讨论】:

    标签: java multithreading


    【解决方案1】:

    volatile 关键字要求在读取和写入变量时满足某些保证。谈论“删除声明”是没有意义的——不,这不可能发生,因为唯一有意义的方法是编译器忽略源代码中的声明。

    但是,如果您在无法判断运行时正在积极满足这些要求的上下文(例如单线程)中运行代码,则 运行时 是允许的跳过那些额外的工作。

    在您的示例中,唯一可能在编译时确定的情况是仅写入而从不读取的变量。在这种情况下,编译器可以跳过写入(如果写入了一个变量,并且周围没有人阅读它,它会发出声音吗?),但 Java 内存模型仍然对 happens-before 做出一些保证 围绕编写 volatile 变量的关系,并且仍然必须维护这些关系,因此在编译时优化它是没有意义的。

    【讨论】:

    • 非常感谢您的回答,现在对我来说更清楚了。但是,即使在编译时忽略 volatile 声明没有意义,如果我理解正确,它在运行时是可能的吗?
    • 另外,如果我们处于您描述的情况,即仅写入的易失性变量,从不读取。即使在运行时,如果允许优化跳过写入,它们仍然必须维护写入前后的发生前关系(即,在写入之后不重新排序先前的语句,在写入时将所有内容刷新到主内存应该发生)?
    • @wiseowl4 如果程序无法观察到差异,我不知道 JLS 或 JVM 规范中有任何内容会禁止 JVM 优化诸如将寄存器刷新到主内存之类的事情。虽然我不知道今天有任何运行时这样做,但我认为这在一些有限的硬件平台上会很有意义,比如嵌入式处理器。关于您的第二条评论,是的,易失性访问仍将充当同步点,因此所有其他发生前的关系都应保持。
    猜你喜欢
    • 1970-01-01
    • 2011-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-29
    相关资源
    最近更新 更多