Java内存模型(Java Memory Model, JMM)
外观
Java内存模型(Java Memory Model, JMM)[编辑 | 编辑源代码]
介绍[编辑 | 编辑源代码]
Java内存模型(JMM)是Java并发编程的核心规范,定义了多线程环境下线程如何与内存交互,确保线程安全性。JMM通过happens-before关系、内存屏障等机制解决可见性、有序性和原子性问题,是理解`synchronized`、`volatile`、`final`等关键字底层原理的基础。
核心概念[编辑 | 编辑源代码]
1. 主内存与工作内存[编辑 | 编辑源代码]
JMM将内存分为两类:
- 主内存(Main Memory):存储所有共享变量的原始值。
- 工作内存(Work Memory):每个线程私有的内存空间,存储线程操作变量的副本。
2. happens-before关系[编辑 | 编辑源代码]
JMM通过以下规则保证操作的有序性:
- 程序顺序规则:同一线程内的操作按代码顺序执行。
- 锁规则:解锁操作先于后续的加锁操作。
- volatile规则:volatile变量的写操作先于后续读操作。
- 线程启动规则:`Thread.start()`先于线程内的任何操作。
- 传递性:若A happens-before B,B happens-before C,则A happens-before C。
代码示例[编辑 | 编辑源代码]
volatile关键字[编辑 | 编辑源代码]
public class VolatileExample {
private volatile boolean flag = false;
public void writer() {
flag = true; // 写操作
}
public void reader() {
if (flag) { // 读操作
System.out.println("Flag is true");
}
}
}
输出(多线程环境下):
Flag is true
解释:`volatile`保证`flag`的修改对所有线程立即可见。
双重检查锁定(DCL)问题[编辑 | 编辑源代码]
public class Singleton {
private static volatile Singleton instance;
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton(); // 非原子操作
}
}
}
return instance;
}
}
解释:`volatile`防止指令重排序,避免返回未初始化的对象。
实际应用场景[编辑 | 编辑源代码]
- 缓存一致性:如Redis分布式锁的实现需遵循JMM。
- 事件驱动架构:如Kafka消费者线程通过`volatile`标志位控制退出。
- 高性能计数器:`AtomicLong`基于CAS和内存屏障实现。
常见问题[编辑 | 编辑源代码]
1. 指令重排序[编辑 | 编辑源代码]
编译器/处理器可能优化指令顺序,JMM通过内存屏障禁止特定重排序。例如:
2. 伪共享(False Sharing)[编辑 | 编辑源代码]
多个线程修改同一缓存行的不同变量会导致性能下降。解决方案:
@Contended // Java 8+注解
private volatile long counter1;
private volatile long counter2;
总结[编辑 | 编辑源代码]
特性 | 实现机制 |
---|---|
`synchronized`、`CAS` | |
`volatile`、`final`、`happens-before` | |
内存屏障、`volatile` |
JMM是编写正确高效并发程序的理论基础,开发者需结合具体场景选择同步策略。