JMM 即 Java 内存模型,它是对共享内存的并发模型。我们知道,Java 中的共享变量是存储在主内存中的,而线程有自己的工作内存,如果一个线程要操作一个共享变量,它会将共享变量赋值一份到自己的工作内存,进行操作后,再将最新的变量值回写到主内存中。
假设有线程 a 对共享变量 x 读取进行更新后及时回写到主内存,然后线程 b 再读取共享变量 x 的值进行操作,这是正常没问题的。但是如果线程 a 对共享变量 x 更新后没有及时回写到主内存,这时线程 b 读取到共享变量 x 的值进行操作,这就出现脏读的现象。
要处理以上并发脏读的问题也简单,可以使用同步机制控制多线程之间操作的顺序,例如使用 synchronzied 关键字;或者使用 volatitle 关键字强制将线程更新后的最新值回写到主内存,以便其他线程可见。这都是 JMM 中 HB 的体现。
我们知道,JVM 会对我们写的代码进行优化,其中一个优化点就是编译器和处理器对指令进行重排序。虽然这些优化能提高程序性能,但是有可能会出现优化后执行的结果不是我们预想的结果,所以需要 happens-before 规则来禁止一些编译优化的场景,保证并发编程的正确性。
JMM 并不是全部禁止指令重排序,对于不会改变程序执行结果的重排序,JMM 允许编译器和处理器这样做。而对于会改变程序执行结果的重排序,JMM 会禁止这种重排序。
以我们最熟悉的 double-check 懒汉式单例模式为例,网上会告知如下程序是没问题的。
package com.chenpi;
/**
-
@Description
-
@Author Mr.nobody
-
@Date 2021/6/22
-
@Version 1.0
*/
public class Singleton {
private