Java 内存模型

48 阅读1分钟

什么是 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 规则。