引言
在多线程编程中,理解内存模型对于编写正确、高效的并发程序至关重要。Java 内存模型(Java Memory Model,JMM)定义了变量的读取和写入如何在多线程环境中进行同步。本文将详细介绍 Java 内存模型的概念、关键特性和实际应用。
1. 什么是 Java 内存模型
Java 内存模型是 Java 语言规范的一部分,它描述了 Java 程序中变量(包括实例字段、静态字段和数组元素)的访问规则以及线程之间如何共享这些变量。JMM 通过规范内存可见性、重排序和同步来确保线程间的正确通信。
2. 内存可见性
内存可见性是指一个线程对变量的修改何时对其他线程可见。JMM 定义了以下几种方式来保证内存可见性:
- volatile 关键字:对
volatile
变量的读写操作具有可见性,确保一个线程对volatile
变量的修改可以被其他线程立即看到。 - synchronized 块:进入
synchronized
块时会获取锁,退出时会释放锁。锁的获取和释放会导致线程工作内存和主内存之间的同步。 - final 关键字:
final
变量在构造函数中一旦初始化完成,确保所有线程都能看到正确的值。
3. 指令重排序
指令重排序是编译器和处理器为了优化性能,对程序指令顺序进行调整的过程。JMM 通过内存屏障和同步操作来控制指令重排序,确保多线程环境下程序的正确性。
3.1 Happens-Before 规则
Happens-Before 规则是 JMM 中定义的用来保证内存可见性和指令重排序的关键规则。以下是一些常见的 Happens-Before 关系:
- 程序顺序规则:在一个线程中,按照程序顺序,前面的操作 Happens-Before 后面的操作。
- 监视器锁规则:对一个锁的解锁 Happens-Before 于随后对这个锁的加锁。
- volatile 变量规则:对一个
volatile
变量的写操作 Happens-Before 于后续对这个volatile
变量的读操作。 - 线程启动规则:对线程对象的
start()
方法调用 Happens-Before 于此线程的每一个动作。 - 线程终止规则:线程中的所有操作 Happens-Before 于其他线程检测到该线程已经终止。
- 传递性:如果 A Happens-Before B,且 B Happens-Before C,则 A Happens-Before C。
4. 同步机制
Java 提供了多种同步机制来保证内存可见性和指令有序性:
4.1 volatile 关键字
volatile
关键字保证了变量的可见性和一定程度的有序性。对 volatile
变量的读写操作不会被重排序。
public class VolatileExample {
private volatile boolean flag = true;
public void writer() {
flag = false;
}
public void reader()