因此,我正在阅读这本书,名为Java并发在实践中,我被困在这个解释,我似乎无法理解,没有一个例子。以下是这段话:
当线程
A写入易失性变量并随后线程B读取该变量时,在写入易失性变量之前对A可见的所有变量的值在读取易失性变量后对B变得可见。
有人能给我一个反例说明为什么“在写入易失性变量之前对A可见的所有变量的值在读取易失变量后对B都是可见的”吗?
我很困惑,为什么在读取易失变量之前,所有其他非易失变量对B都不可见?
发布于 2011-06-07 01:21:41
线程B可能有这些变量的CPU本地缓存。对易失性变量的读取确保从对易失性的前一次写入中看到的任何中间缓存刷新。
例如,请阅读以下链接,该链接的结尾是“使用易失性修复双重检查锁定”:
http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
发布于 2011-06-07 01:20:19
声明易失性Java变量意味着:
仅供参考,什么时候需要易失性?
当多个线程使用相同的变量时,每个线程都将拥有该变量的本地缓存的副本。因此,当它更新值时,它实际上是在本地缓存中更新的,而不是在主变量内存中。使用相同变量的另一个线程不知道其他线程更改的值。为了避免此问题,如果您将一个变量声明为易失性变量,则它将不会存储在本地缓存中。每当线程更新这些值时,都会将其更新到主内存。因此,其他线程可以访问更新的值。
从JLS§17.4.7格式良好的执行
我们只考虑行刑。如果下列条件成立,则执行E=< P、A、po、so、W、V、sw、hb >的格式良好:
有用的链接:关于Java中的非阻塞并发性,我们到底知道些什么?
发布于 2011-06-07 01:49:30
如果一个变量是非易失性的,那么编译器和CPU可以根据他们认为合适的情况自由地重新排序指令,以便优化性能。
如果变量现在被声明为可变变量,那么编译器就不再试图优化对该变量的访问(读和写)。但是,它可能继续优化其他变量的访问。
在运行时,当访问易失性变量时,JVM向CPU生成适当的内存屏障指令。内存屏障具有同样的目的-- CPU也可以防止重新排序指令.
当一个易失性变量被写入(通过线程A)时,对任何其他变量的所有写入都完成(或至少看起来是这样),并且在写入易失性变量之前使A可见;这通常是由于内存写屏障指令。同样,对其他变量的任何读取都将在读取(线程B)之前完成(或看起来是);这通常是由于内存读取障碍指令。这种由屏障强制执行的指令排序,将意味着所有对A可见的写入都将是可见的。然而,这并不意味着没有发生任何指令的重新排序(编译器可能对其他指令执行了重新排序);它仅仅意味着,如果任何对A可见的写入发生了,则对B是可见的。简单地说,这意味着严格的程序顺序不被维护。
如果您想更详细地了解JVM是如何发出内存障碍指令的,我将在内存屏障和JVM并发上指出这篇文章。
相关问题
https://stackoverflow.com/questions/6259745
复制相似问题