Java内存模型(JMM)是一套抽象规范,而非物理内存映射,它通过主内存与工作内存的抽象、八大原子操作及happens-before规则,统一解决多线程下的可见性、原子性、有序性问题,并为volatile、synchronized等机制提供理论基础。

Java 内存模型(JMM)不是物理内存的映射,而是一套规范——它定义了多线程环境下,变量如何在主内存与线程工作内存之间读写、同步与可见,以及哪些重排序是被允许的。配一套系统梳理教程,关键不在堆砌概念,而在厘清“为什么需要 JMM”“它管什么、不管什么”“怎么用它解释实际问题”。下面给出清晰、可落地的结构建议:
一、从并发 bug 倒推:为什么 Java 需要内存模型
不讲抽象定义,先展示真实问题:比如两个线程对同一 volatile 变量做自增,结果少于预期;或一个线程写完 flag = true 和 data = 42,另一个线程看到 flag == true 却读到 data == 0。这些不是 JVM Bug,而是硬件缓存、编译器优化、CPU 指令重排共同导致的“看似不合理”行为。教程开头就用这类可复现的小例子切入,让学习者意识到:JMM 是为了解决“程序在多核+优化环境下的语义一致性”问题。
二、核心三要素:原子性、可见性、有序性,各自靠什么保障
这不是罗列关键词,而是对应到具体机制:
- 可见性:靠 volatile 读写屏障、synchronized 解锁/加锁时的内存刷新、final 字段的初始化安全保证;注意区分 volatile 不保证原子性(如 i++)
- 有序性:靠 happens-before 规则(程序次序、监视器锁、volatile 变量、线程启动/终止、传递性等)约束重排序边界;强调它不是禁止重排,而是规定哪些重排“对其他线程不可见”
- 原子性:JMM 本身不提供原子性,而是依赖 synchronized、Lock 或 CAS 类操作;long/double 的非原子性读写仅在 32 位 JVM 上需关注(现代基本可忽略)
三、happens-before 是理解 JMM 的钥匙,不是玄学
很多教程把它讲成“必须背的八条规则”,其实它本质是“程序员可推理的、安全的执行顺序契约”。重点讲清楚:
立即学习“Java免费学习笔记(深入)”;
- 每条规则对应的典型场景(例如:A 线程 unlock M,B 线程 lock M → A 对 M 的修改对 B 可见)
- 如何用它分析代码(画出 hb 图,看是否存在链路)
- 常见误区:hb 规则不等于执行顺序,也不解决所有竞态;它只是“如果满足 hb,则结果不会比按顺序执行更差”
四、结合 JDK 工具和典型模式,落地验证
避免纯理论,配上可动手的部分:
- 用 JOL(Java Object Layout)查看对象内存布局,理解对象头中 Mark Word 与锁升级的关系
- 用 JITWatch 或 -XX:+PrintAssembly(配合 hsdis)观察 synchronized 或 volatile 编译后的内存屏障指令(如 lock addl $0x0, (%rsp))
- 对比几种单例实现(饿汉、DCL、static holder),逐行标注 hb 边界,说明为何 DCL 必须加 volatile


















