易失性:为什么要阻止编译器重新排序代码
在java中,据我所知,volatile变量使线程直接读/写到主CPU(而不是每个线程的缓存中),因此将其更改显示给其他线程。
我不知道的是:那么,为什么这个工作(volatile)可以阻止编译器/ CPU重新排序代码语句。
谢谢 :)
这是一个非常好的例子,说明禁止重新排序旨在解决的问题(取自此处 ):
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
不是。 如果同时执行writer和reader并且读者将v
设置为true
,则x
保证为42
。 在Java-5之前,编译器可以自由地重写对x
和v
的写入,因此在看到v
set为true
之后 ,你可以看到x
为零。 这令人困惑,并导致微妙的错误。 Java-5内存模型通过使易失性写入几乎等同于同步来解决此问题。
这就是语言的定义方式。 非正式地,在Java中标记变量volatile
特别告诉编译器它不应该重新排序它周围的语句或优化它的值,因为该值可能在另一个线程中同时被修改。 然后,JVM的特定实现负责遵守此volatile
修饰符并采取适当的预防措施,以避免错误地优化程序。
如果您想了解有关确保volatile
正常工作的语言级保证的更多具体细节,您可能需要查看Java语言规范对Java内存模型的描述,该描述定义了管理线程行为的抽象规则。 它还描述了volatile
如何与这些规则交互。
希望这可以帮助!