我最近正在阅读 Crack Code Interview 这本书,但是第257页有一段令我困惑:
线程是进程的特定执行路径;当一个线程修改进程资源时,对兄弟线程立即可以看到更改。
IIRC,如果一个线程对变量进行了更改,则更改将首先保存在CPU缓存中(例如,L1缓存),并且不保证与其他线程同步,除非该变量被声明为volatile。
我是对的吗?
答案 0 :(得分:10)
每个现代多核CPU都有硬件cache coherence。 L1和类似的缓存是不可见的。像L1缓存这样的CPU缓存有 nothing 与内存可见性有关。
当线程修改进程资源时,更改立即可见。问题是优化导致流程资源不能按照代码指定的顺序进行修改。
如果您的代码有k = j; i = 4; if (j == 2) foo();
,优化程序可能会看到您的第一个作业读取j
的值。因此,当您将其与2
进行比较时,它可能不会再次阅读它,因为它“知道”它无法更改。但是,另一个线程可能已经改变了它。因此,当需要线程之间的同步时,需要禁用某些类型的优化。这就像volatile
这样的事情。
如果编译器和CPU没有进行优化并且在编写程序时完全执行了程序,则永远不需要volatile
。内存可见性是关于代码的优化(一些由编译器完成,一些由CPU完成),而不是缓存。
答案 1 :(得分:1)
我认为您引用的文字不正确。 Java内存模型的整个概念是通过现代软件来处理复杂的优化。硬件,以便程序员可以确定其他线程中相应读取可见的写入内容。
除非Java中的程序正确同步,否则您无法保证一个线程的更改对其他线程立即可见。也许文本指的是一个非常具体(和弱)的内存模型。
使用volatile变量只是同步线程的一种方法,并不适合所有场景。
<强> - 编辑 - 强>
我想我现在理解这种困惑......我同意David Schwartz,假设:
1)“修改进程资源”是指资源的实际更改,而不仅仅是执行以某种高级计算机语言编写的写入指令。
2)“兄弟线程立即可见”意味着其他线程能够看到它;这并不意味着你的程序中的一个线程必然会看到它。您可能仍需要使用同步工具来禁用绕过对资源的实际访问的优化。