跳转到内容

JMM 内存模型与 happens-before 规则

Java 程序运行在多核 CPU 上,每个线程有自己的工作内存(CPU 缓存 / 寄存器),不会直接读写主内存。

这导致三类问题:

问题含义典型症状
可见性A 线程的写,B 线程不一定能看到B 永远读到初始值
原子性操作不可分割性被破坏i++ 丢失更新
有序性编译器 / CPU 对指令重排序对象”半初始化”就被其他线程读到

JMM 用 8 个操作描述主内存与工作内存之间的交互(了解即可,实际编程不直接用):

read → load → use → assign → store → write
lock / unlock(针对主内存变量)
  • read / load:从主内存读取到工作内存
  • use / assign:线程执行引擎与工作内存交互
  • store / write:从工作内存写回主内存

JMM 不保证”随时可见”,但通过 happens-before 给出确定性承诺:

规则内容
程序顺序规则同线程内,前面的操作 hb 后面的操作
监视器锁规则unlock hb 后续对同一锁的 lock
volatile 变量规则volatile 写 hb 后续对同变量的读
线程启动规则start() hb 新线程中的任意操作
线程终止规则线程所有操作 hb join() 返回
传递性规则A hb B,B hb C,则 A hb C
可见性 → volatile / synchronized / final
原子性 → synchronized / Lock / Atomic 原子类
有序性 → volatile(内存屏障)/ synchronized

Q:JMM 与 JVM 内存结构(堆/栈/方法区)是一回事吗?

A:不是。JMM 是并发语义规范,描述线程间如何共享变量;JVM 内存结构是运行时内存划分,描述数据存在哪里。两者维度不同。

Q:happens-before 能保证原子性吗?

A:不能。happens-before 只保证可见性和有序性,原子性需要 synchronized 或原子类来保证。

Q:指令重排序有哪几个层次?

A:三个层次——①编译器重排序;②CPU 指令级并行重排序;③内存系统重排序(缓存、写缓冲区)。JMM 通过内存屏障(Memory Barrier)屏蔽底层差异。