JMM内存模型解析

JMM(Java Memory Model,Java 内存模型)是 Java 虚拟机(JVM)规范中定义的一种抽象模型,用于描述多线程环境下,线程如何与内存交互以及如何保证内存的可见性、有序性和原子性。JMM 的主要目标是解决多线程并发编程中的内存一致性问题。以下是 JMM 的主要组成部分及其详细解析:


1. 主内存(Main Memory)

  • 定义
    • 主内存是所有线程共享的内存区域,存储了所有的变量(包括实例字段、静态字段等)。
  • 特点
    • 主内存是线程之间通信的桥梁。
    • 线程对变量的读写操作最终都会反映到主内存中。

2. 工作内存(Working Memory)

  • 定义
    • 每个线程都有自己的工作内存,工作内存是线程私有的内存区域。
    • 工作内存存储了线程对主内存中变量的副本。
  • 特点
    • 线程对变量的所有操作(读取、赋值等)都在工作内存中进行。
    • 线程不能直接操作主内存中的变量,而是通过工作内存间接操作。

3. 内存间的交互操作

JMM 定义了以下 8 种原子操作,用于描述主内存和工作内存之间的交互:

操作 作用
lock(锁定) 作用于主内存的变量,将其标识为线程独占状态。
unlock(解锁) 作用于主内存的变量,释放锁定状态。
read(读取) 作用于主内存的变量,将变量的值从主内存传输到工作内存。
load(载入) 作用于工作内存的变量,将 read 操作得到的值放入工作内存的变量副本中。
use(使用) 作用于工作内存的变量,将变量的值传递给执行引擎。
assign(赋值) 作用于工作内存的变量,将执行引擎接收到的值赋给工作内存的变量。
store(存储) 作用于工作内存的变量,将变量的值传输到主内存。
write(写入) 作用于主内存的变量,将 store 操作得到的值放入主内存的变量中。

4. 内存模型的三大特性

JMM 的核心目标是保证多线程环境下的内存可见性、有序性和原子性。

(1) 可见性(Visibility)

  • 定义
    • 当一个线程修改了共享变量的值,其他线程能够立即看到修改后的值。
  • 实现机制
    • 通过 volatile 关键字、synchronized 锁、final 关键字等保证可见性。

(2) 有序性(Ordering)

  • 定义
    • 程序执行的顺序按照代码的先后顺序执行。
  • 实现机制
    • 通过 volatile 关键字、synchronized 锁、happens-before 规则等保证有序性。

(3) 原子性(Atomicity)

  • 定义
    • 一个操作是不可中断的,要么全部执行成功,要么全部不执行。
  • 实现机制
    • 通过 synchronized 锁、java.util.concurrent.atomic 包中的原子类等保证原子性。

5. Happens-Before 规则

Happens-Before 是 JMM 中定义的一组规则,用于描述操作之间的可见性和有序性。以下是 Happens-Before 的主要规则:

规则 描述
程序顺序规则 在一个线程中,前面的操作 Happens-Before 后面的操作。
锁规则 解锁操作 Happens-Before 后续的加锁操作。
volatile 变量规则 volatile 变量的写操作 Happens-Before 后续的读操作。
线程启动规则 线程的 start() 方法 Happens-Before 该线程的任何操作。
线程终止规则 线程的所有操作 Happens-Before 其他线程检测到该线程已经终止。
线程中断规则 对线程的 interrupt() 方法 Happens-Before 被中断线程检测到中断事件。
对象终结规则 对象的构造函数 Happens-Before 该对象的 finalize() 方法。
传递性规则 如果 A Happens-Before B,且 B Happens-Before C,那么 A Happens-Before C。

6. volatile 关键字

volatile 是 JMM 中用于保证可见性和有序性的关键字。

(1) 可见性

  • volatile 变量的写操作会立即刷新到主内存。
  • volatile 变量的读操作会从主内存中读取最新的值。

(2) 有序性

  • 禁止指令重排序优化,确保 volatile 变量的读写操作按照代码顺序执行。

7. synchronized 关键字

synchronized 是 JMM 中用于保证可见性、有序性和原子性的关键字。

(1) 可见性

  • 线程在进入 synchronized 块时,会清空工作内存中的变量副本,从主内存中重新读取。
  • 线程在退出 synchronized 块时,会将工作内存中的变量副本写回主内存。

(2) 有序性

  • synchronized 块内的操作不会被重排序到块外。

(3) 原子性

  • synchronized 块内的操作是不可分割的,确保线程安全。

8. final 关键字

final 是 JMM 中用于保证可见性的关键字。

(1) 可见性

  • final 修饰的字段在构造函数中初始化后,对其他线程立即可见。

(2) 禁止重排序

  • 禁止对 final 字段的写操作重排序到构造函数之外。

9. 总结

JMM 是 Java 多线程编程的核心基础,它通过定义主内存、工作内存和内存间交互操作,解决了多线程环境下的内存一致性问题。JMM 的三大特性(可见性、有序性、原子性)以及 Happens-Before 规则,为开发者提供了编写线程安全程序的指导。理解 JMM 的组成部分及其工作原理,有助于更好地掌握 Java 并发编程。