200字
聊聊JMM
2025-06-25
2025-06-25

Java Memory Model(JMM,Java 内存模型)是 Java 虚拟机(JVM)中用于定义线程之间共享变量如何在内存中读写的规范和机制。它解决了在并发编程中最核心的两个问题:

  1. 可见性(Visibility)

  2. 有序性(Ordering)

下面是对 Java Memory Model 的系统性介绍:


🧠 一、Java Memory Model 的目的

JMM 的设计目标是为了屏蔽底层硬件和操作系统的差异,让 Java 程序在不同平台上的多线程行为具备一致性。它定义了:

  • 线程之间共享变量的访问规则。

  • JVM 以及编译器在执行时对代码重排序的边界。

  • volatile、synchronized 等关键字的语义保证。


📦 二、主内存与工作内存

在 JMM 中,每个线程有:

  • 主内存(Main Memory):所有共享变量的真实存储位置。

  • 工作内存(Working Memory):每个线程自己的缓存副本,用于提高性能。

执行流程:

  1. 线程从主内存中读取共享变量副本到工作内存。

  2. 对变量的所有读写必须在工作内存中进行。

  3. 最终会将修改后的值刷新回主内存。

这就会引发“可见性”问题 —— 一个线程对变量的修改,另一个线程可能看不到。


🔁 三、JMM 中的重排序

现代处理器和编译器为了优化性能,会对指令进行 重排序(Reordering)。JMM 允许以下三种重排序:

  1. 编译器优化重排序:编译器在不改变单线程语义的前提下,调整代码顺序。

  2. 处理器指令重排序:CPU 在执行时对指令重新排序。

  3. 内存系统重排序:不同线程看到的变量修改顺序不同。

JMM 为此引入了 happens-before 原则,来规范什么顺序是“合法”的。


⛓️ 四、Happens-Before 原则

happens-before 是 JMM 的核心原则,它规定了操作之间的执行先后关系,用于保证可见性与有序性。

一些常见的 happens-before 规则:

  • 程序顺序规则:一个线程内,前面的操作先于后面的操作。

  • 监视器锁规则:对一个锁的 unlock 操作先于对同一个锁的 lock。

  • volatile 规则:对一个 volatile 变量的写操作先于后续对该变量的读操作。

  • 线程启动规则:Thread.start() 先于该线程的任何操作。

  • 线程终止规则:线程中的所有操作先于其他线程检测到它结束。


🧩 五、volatile 与 JMM

volatile 关键字是 JMM 的直接产物,它有两个核心语义:

  1. 保证可见性:写入一个 volatile 变量,相当于刷新到主内存;读取 volatile 变量前强制从主内存拉取。

  2. 禁止指令重排序:它会插入内存屏障,防止该变量周围的操作被重排序。

但它不保证原子性,比如 i++ 不是原子操作,即使 i 是 volatile。


🔒 六、JMM 与 synchronized

synchronized 同样依赖 JMM:

  • 进入 synchronized 块时:读取变量并清空工作内存。

  • 退出 synchronized 块时:刷新变量到主内存。

这保证了代码块中的变量读写对其他线程是可见有序的。


⚠️ 七、JMM 的实际意义

理解 JMM 可以帮助:

  • 正确使用 volatile、synchronized 和 Atomic 工具类。

  • 避免并发编程中的“脏读”、“乱序执行”、“不可见”等问题。

  • 编写线程安全的类与组件。


Comment