Java 内存模型(Java Memory Model, JMM) 是 Java 虚拟机(JVM)定义的一种规范,用于描述多线程环境下,线程如何与主内存和工作内存交互,以及如何保证线程之间的可见性、有序性和原子性。JMM 是 Java 并发编程的基础,它定义了线程之间的通信规则,确保多线程程序在不同平台上的行为一致。
1. JMM 的核心概念
JMM 主要围绕以下几个核心概念展开:
(1)主内存(Main Memory)
- 主内存是所有线程共享的内存区域,存储了所有的变量(实例字段、静态字段等)。
- 主内存是线程通信的桥梁。
(2)工作内存(Working Memory)
- 每个线程都有自己的工作内存,存储了线程对变量的副本。
- 线程对变量的所有操作(读取、赋值等)都在工作内存中进行,不能直接操作主内存。
(3)内存间的交互
- 线程通过以下操作与主内存交互:
- read:从主内存读取变量到工作内存。
- load:将读取的变量值放入工作内存的变量副本中。
- use:线程使用工作内存中的变量值。
- assign:线程将新的值赋给工作内存中的变量。
- store:将工作内存中的变量值写回主内存。
- write:将存储的变量值更新到主内存中。
2. JMM 的三大特性
JMM 的核心目标是解决多线程环境下的 可见性、有序性 和 原子性 问题。
(1)可见性(Visibility)
- 一个线程对共享变量的修改,能够及时被其他线程看到。
- JMM 通过以下机制保证可见性:
volatile
关键字:确保变量的修改对所有线程立即可见。synchronized
关键字:在释放锁之前,将工作内存中的变量刷新到主内存。final
关键字:确保构造器中的赋值操作对其他线程可见。
(2)有序性(Ordering)
- 程序执行的顺序按照代码的先后顺序执行。
- JMM 通过以下机制保证有序性:
volatile
关键字:禁止指令重排序。synchronized
关键字:确保同一时刻只有一个线程执行同步代码块。happens-before
规则:定义了一系列操作之间的先后顺序。
(3)原子性(Atomicity)
- 一个操作是不可分割的,要么全部执行成功,要么全部不执行。
- JMM 通过以下机制保证原子性:
synchronized
关键字:确保同步代码块的原子性。- 原子类(如
AtomicInteger
):通过 CAS 操作保证原子性。
3. happens-before
规则
happens-before
是 JMM 中定义的一种偏序关系,用于描述操作之间的可见性和有序性。以下是常见的 happens-before
规则:
- 程序顺序规则:同一线程中的操作,前面的操作
happens-before
后面的操作。 - 锁规则:解锁操作
happens-before
后续的加锁操作。 volatile
规则:写volatile
变量happens-before
读volatile
变量。- 传递性规则:如果 A
happens-before
B,且 Bhappens-before
C,那么 Ahappens-before
C。
4. JMM 与硬件内存模型的关系
- JMM 是一个抽象的概念,它屏蔽了底层硬件内存模型的差异(如 CPU 缓存、指令重排序等)。
- JMM 通过定义统一的规则,确保 Java 程序在不同硬件平台上的一致性。
5. 示例
以下是一个简单的示例,展示了 volatile
关键字如何保证可见性:
public class VisibilityExample {
private volatile boolean flag = false;
public void writer() {
flag = true; // 写操作
}
public void reader() {
while (!flag) {
// 等待 flag 变为 true
}
System.out.println("Flag is true");
}
}
在这个例子中,volatile
确保了 writer()
线程对 flag
的修改对 reader()
线程立即可见。
6. 总结
- Java 内存模型(JMM) 是 Java 并发编程的基础,定义了多线程环境下线程如何与内存交互。
- JMM 通过 可见性、有序性 和 原子性 三大特性,确保多线程程序的正确性。
happens-before
规则是 JMM 的核心,用于描述操作之间的顺序关系。- JMM 屏蔽了底层硬件的差异,为 Java 程序提供了统一的内存模型。
THE END
暂无评论内容