易失性:为什么要阻止编译器重新排序代码

时间:2012-02-08 03:34:48

标签: java multithreading volatile

在java中,据我所知,volatile变量使一个线程直接读/写到主CPU(而不是每个线程的缓存中),因此将其更改显示给其他线程。

我不知道的是:那么,为什么这个(volatile的)工作可以阻止编译器/ CPU重新排序代码语句。

谢谢:)

2 个答案:

答案 0 :(得分:20)

这是一个非常好的例子,说明禁止重新排序旨在解决的问题(取自here):

class VolatileExample {
    int x = 0;
    volatile boolean v = false;
    public void writer() {
        x = 42;
        v = true;
    }
    public void reader() {
        if (v == true) {
            //uses x - guaranteed to see 42.
        }
    }
}

在此示例中,v是易变的,但x不是。如果同时执行作者和读者,并且读者将v设置为true,则x保证为42。在Java-5之前,编译器可以自由地将写入重新排序为xv,因此您可以在之后看到x 看到v设置为true。这令人困惑,并导致微妙的错误。 Java-5内存模型通过使易失性写入几乎等同于同步来解决此问题。

答案 1 :(得分:5)

这就是语言的定义方式。非正式地,在Java中标记变量volatile特别告诉编译器它不应该重新排序它周围的语句或优化它的值,因为该值可能在另一个线程中同时修改。然后,JVM的特定实现负责尊重此volatile修饰符,并采取适当的预防措施,不要错误地优化程序。

如果您想了解有关确保volatile正常工作的语言级保证的更多具体细节,您可能需要查看the Java Language Specification's description of the Java memory model,它定义了管理线程行为的抽象规则。它还描述了volatile如何与这些规则进行互动。

希望这有帮助!