什么是 Java 内存模型?
Java 内存模型规范了 JVM 如何提供按需禁用缓存和编译优化的方法。
具体来说,这些方法包括 volatile、synchronized 和 final 三个关键字,以及六项 Happens-Before 规则。
使用 volatile 的困惑
class VolatileExample {
int x = 0;
volatile boolean v = false;
public void writer() {
x = 42;
v = true;
}
public void reader() {
if (v == true) {
// 这里x会是多少呢?
}
}
}
例如下面的示例代码,
假设线程 A 执行 writer() 方法,按照 volatile 语义,会把变量 “v=true” 写入内存;
假设线程 B 执行 reader() 方法,同样按照 volatile 语义,线程 B 会从内存中读取变量 v,
如果线程 B 看到 “v == true” 时,那么线程 B 看到的变量 x 是多少呢?
直觉上看,应该是 42,那实际应该是多少呢?
这个要看 Java 的版本,如果在低于 1.5 版本上运行,x 可能是 42,也有可能是 0;如果在 1.5 以上的版本上运行,x 就是等于 42。
分析一下,为什么 1.5 以前的版本会出现 x = 0 的情况呢?
变量 x 可能被 CPU 缓存而导致可见性问题。
这个问题在 1.5 版本已经被圆满解决了。
Java 内存模型在 1.5 版本对 volatile 语义进行了增强。
怎么增强的呢?答案是一项 Happens-Before 规则。
Happens-Before 规则
定义 : 前面一个操作的结果对后续操作是可见的
Happens-Before 约束了编译器的优化行为,虽允许编译器优化,但是要求编译器优化后一定遵守 Happens-Before 规则。