Java内存模型(JMM)是规范多线程下共享变量访问的抽象模型,核心解决可见性、有序性、原子性三大问题,依赖synchronized、volatile、final等机制协同保障,其中volatile保证单变量读写可见与相关指令禁止重排但不保证复合操作原子性,synchronized提供三者统一保障并支持线程协作,final则通过happens-before语义确保正确构造对象的初始化安全与安全发布。

Java内存模型(JMM)是大厂面试中并发模块的必考点,不是背概念就能过关——考官真正想看的是你能不能把“可见性、有序性、原子性”这三件事,和 synchronized、volatile、final、Lock 等具体机制串起来讲清楚。
JMM核心要讲清三个问题
别一上来就堆术语。面试时建议用“问题驱动”方式展开:
- 为什么多个线程读写同一个变量,一个线程改了,另一个线程看不到?→ 引出可见性(主内存 vs 工作内存,缓存不一致)
- 代码里 a=1; b=2;,为什么实际执行可能是 b 先赋值?→ 引出有序性(编译器重排序、处理器指令重排)
- i++ 看似一行,为什么多线程下结果常出错?→ 引出原子性(读-改-写三步非原子,中间可能被抢占)
volatile 关键在“做什么”和“不做什么”
这是高频陷阱题。不能只说“保证可见性”,必须点明边界:
- 它强制每次读都从主内存取,每次写都立即刷回主内存 → 解决可见性
- 它禁止该变量前后的指令与其发生重排序 → 解决有序性(但仅限于该变量相关指令)
- 它不保证复合操作的原子性:比如 count++、flag = !flag 都不行
- 典型适用场景:状态标志(running = false)、双重检查锁里的单例引用
对比 synchronized 和 volatile 的使用分寸
考官常问:“既然 volatile 轻量,为啥还要 synchronized?”答案要落在责任边界上:
立即学习“Java免费学习笔记(深入)”;
- volatile:适合单一变量的读写同步,无锁、开销小,但能力有限
- synchronized:提供原子性 + 可见性 + 有序性三位一体保障,还能配合 wait/notify 做线程协作
- 举例:计数器递增必须用 synchronized 或 AtomicInteger;开关控制用 volatile 更合适
final 字段的特殊地位容易被忽略
JMM 对 final 有专门语义保证,这点很多人没讲透:
- 构造器内对 final 字段的写入,与对象引用的发布之间存在 happens-before 关系
- 只要对象是正确构造的(没有 this 逃逸),其他线程看到的 final 字段一定是初始化值,无需额外同步
- 这是安全发布不可变对象(如 String、LocalDate)的底层依据


















