Java中的易失性变量
因此,我正在阅读这本名为Java Concurrency in Practice的书,并且我被这个解释所困扰,如果没有示例,我似乎无法理解它。这是引用:
当线程
A
写入易失性 变量和随后的线程B
读取同一个变量,值 所有可见的变量A
在写入易失性之前 之后变量对B
可见 读取易失性变量。
有人可以给我一个反例,解释为什么“在写入易失性变量之前对A
可见的所有变量的值在读取易失性变量之后对B
变得可见” ?
我很困惑为什么在读取易失性变量之前所有其他非易失性变量对 B 不可见?
So I am reading this book titled Java Concurrency in Practice and I am stuck on this one explanation which I cannot seem to comprehend without an example. This is the quote:
When thread
A
writes to a volatile
variable and subsequently threadB
reads that same variable, the values
of all variables that were visible toA
prior to writing to the volatile
variable become visible toB
after
reading the volatile variable.
Can someone give me a counterexample of why "the values of ALL variables that were visible to A
prior to writing to the volatile variable become visible to B
AFTER reading the volatile variable"?
I am confused why all other non-volatile variables do not become visible to B
before reading the volatile variable?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
声明一个易失性 Java 变量意味着:
仅供参考,什么时候需要 volatility ?
来自 JLS §17.4.7 < em>格式良好的执行
有用的链接:做什么我们真的了解 Java 中的非阻塞并发吗?
Declaring a volatile Java variable means:
Just for your reference, When is volatile needed ?
From JLS §17.4.7 Well-Formed Executions
Useful Link : What do we really know about non-blocking concurrency in Java?
线程 B 可能具有这些变量的 CPU 本地缓存。读取易失性变量可确保观察到先前写入易失性变量的任何中间缓存刷新。
有关示例,请阅读以下链接,其结尾为“使用 Volatile 修复双重检查锁定”:
http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
Thread B may have a CPU-local cache of those variables. A read of a volatile variable ensures that any intermediate cache flush from a previous write to the volatile is observed.
For an example, read the following link, which concludes with "Fixing Double-Checked Locking using Volatile":
http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
如果变量是非易失性的,则编译器和 CPU 可以根据需要自由地重新排序指令,以优化性能。
如果该变量现在被声明为易失性,则编译器不再尝试优化对该变量的访问(读取和写入)。然而,它可能会继续优化其他变量的访问。
在运行时,当访问易失性变量时,JVM 会向 CPU 生成适当的内存屏障指令。内存屏障具有相同的目的——CPU 也被阻止重新排序指令。
当(由线程 A)写入 易失性变量时,对任何其他变量的所有写入都已完成(或至少看起来),并且在写入易失性变量之前对 A 可见;这通常是由于内存写入屏障指令造成的。同样,对其他变量的任何读取都将在
读取(由线程 B);这通常是由于内存读取屏障指令造成的。由屏障强制执行的指令排序意味着所有对 A 可见的写入对 B 都可见。但是,这并不意味着指令的任何重新排序尚未发生了(编译器可能对其他指令执行了重新排序);它只是意味着如果发生了对 A 可见的任何写入,那么它对 B 也是可见的。简单来说,这意味着不维护严格的程序顺序。
如果您想了解如何JVM 发出更详细的内存屏障指令。
相关问题
If a variable is non-volatile, then the compiler and the CPU, may re-order instructions freely as they see fit, in order to optimize for performance.
If the variable is now declared volatile, then the compiler no longer attempts to optimize accesses (reads and writes) to that variable. It may however continue to optimize access for other variables.
At runtime, when a volatile variable is accessed, the JVM generates appropriate memory barrier instructions to the CPU. The memory barrier serves the same purpose - the CPU is also prevent from re-ordering instructions.
When a volatile variable is written to (by thread A), all writes to any other variable are completed (or will atleast appear to be) and made visible to A before the write to the volatile variable; this is often due to a memory-write barrier instruction. Likewise, any reads on other variables, will be completed (or will appear to be) before the
read (by thread B); this is often due to a memory-read barrier instruction. This ordering of instructions that is enforced by the barrier(s), will mean that all writes visible to A, will be visible B. This however, does not mean that any re-ordering of instructions has not happened (the compiler may have performed re-ordering for other instructions); it simply means that if any writes visible to A have occurred, it would be visible to B. In simpler terms, it means that strict-program order is not maintained.
I will point to this writeup on Memory Barriers and JVM Concurrency, if you want to understand how the JVM issues memory barrier instructions, in finer detail.
Related questions
允许线程缓存其他线程在读取后可能已更新的变量值。
volatile
关键字强制所有线程不缓存值。Threads are allowed to cache variable values that other threads may have since updated since they read them. The
volatile
keyword forces all threads to not cache values.如果您使用易失性变量,这只是内存模型给您带来的额外好处。
通常(即在没有易失性变量和同步的情况下),VM 可以使一个线程中的变量按其想要的任何顺序对其他线程可见,或者根本不可见。例如,读取线程可以读取另一个线程变量分配的早期版本的某种混合。这是由于线程可能在具有自己的缓存的不同 CPU 上运行,这些线程仅有时被复制到“主内存”,此外还通过出于优化目的的代码重新排序而导致。
如果你使用了 volatile 变量,一旦线程 B 从中读取了一些值 X,VM 就会确保线程 A 在写入 X 之前写入的任何内容对 B 也是可见的。(并且 A 保证可见的所有内容也可见) ,传递)。
同步块和其他类型的锁也有类似的保证。
This is simply an additional bonus the memory model gives you, if you work with volatile variables.
Normally (i.e. in the absence of volatile variables and synchronization), the VM can make variables from one thread visible to other threads in any order it wants, or not at all. E.g. the reading thread could read some mixture of earlier versions of another threads variable assignments. This is caused by the threads being maybe run on different CPUs with their own caches, which are only sometimes copied to the "main memory", and additionally by code reordering for optimization purposes.
If you used a volatile variable, as soon as thread B read some value X from it, the VM makes sure that anything which thread A has written before it wrote X is also visible to B. (And also everything which A got guaranteed as visible, transitively).
Similar guarantees are given for synchronized blocks and other types of locks.