Skip to content

08 - Java 内存模型与并发

定位: Java 内存模型是连接 Java 并发编程与硬件内存模型的桥梁——定义了一组规则,让程序员写出可预期的多线程代码,同时为 JVM 实现者保留优化空间。 面试高频度: ⭐⭐⭐⭐⭐

一、为什么需要 JMM?

硬件现实:CPU 不是按直觉工作的

现代 CPU 为了性能,做了三件"破坏直觉"的事:

CPU Core 0                     CPU Core 1
┌──────────────────┐          ┌──────────────────┐
│  寄存器           │          │  寄存器           │
├──────────────────┤          ├──────────────────┤
│  L1 Cache (快)    │          │  L1 Cache (快)    │
├──────────────────┤          ├──────────────────┤
│  L2 Cache         │          │  L2 Cache         │
├──────────────────┤          ├──────────────────┤
│  Store Buffer     │          │  Store Buffer     │← 写操作先写这里(异步!)
└────────┬─────────┘          └────────┬─────────┘
         │                             │
         └──────────L3 Cache───────────┘

                 ┌─────┴─────┐
                 │  Main Memory  │
                 └──────────────┘

三个硬件优化

  1. CPU Cache:每个核心有自己的 L1/L2 缓存。Thread A 的写可能只停留在 A 的 L1 中,Thread B 读不到。
  2. Store Buffer:写操作先进入 Store Buffer(异步),批量刷入缓存。其他核心在写入缓存前看不到新值。
  3. 指令重排序:CPU + 编译器都会重排序——只要不改变单线程执行结果。但多线程角度看,顺序可能完全错乱。

Consequence:没有 JMM 规则,x=1; y=2 可能被观察为 y=2; x=0(Store Buffer 延迟)。多线程程序的正确性完全不可预期。

JMM 的角色

JMM 不是一个"真实的内存层",而是一组抽象规则——定义了线程何时能看到共享变量的最新值(可见性),以及哪些顺序保证成立(有序性)。

硬件混乱的现实              JMM 抽象规则              Java 程序员眼中的世界
┌──────────────────┐     ┌──────────────────┐     ┌──────────────────┐
│ CPU 重排序       │────→│ happens-before   │────→│ "看起来像顺序一  │
│ Store Buffer     │     │ volatile 语义     │     │  致性"            │
│ Cache 不一致     │     │ final 语义        │     │  (实际上编译器   │
│ 编译器优化       │     │ synchronized 规则  │     │   在规则内重排序) │
└──────────────────┘     └──────────────────┘     └──────────────────┘
      混乱                     有规则                      可预期

二、子专题导航

#主题面试频率核心内容
**JMM与happens-before**JMM 与 happens-before⭐⭐⭐⭐⭐JMM 本质、8 条 happens-before 规则、可见性保证的本质
**volatile的内存语义**volatile 内存语义⭐⭐⭐⭐⭐可见性、禁止重排序、内存屏障、DCL 问题
**final的内存语义**final 内存语义⭐⭐⭐⭐JSR-133 修复、构造函数逃逸、不可变保证范围
**synchronized的JVM实现**synchronized 底层实现⭐⭐⭐⭐⭐monitorenter/monitorexit、ObjectMonitor、MarkWord 锁状态
**锁升级过程**锁升级完整过程⭐⭐⭐⭐⭐偏向锁→轻量锁→重量锁、MarkWord 变换、批量重偏向/撤销

三、核心概念全景

┌─────────────────────────────────────────────────────────────────────────┐
│                    JMM 体系全景图                                          │
│                                                                         │
│  ┌──────────────────────────────────────────────────────────────────┐   │
│  │                     Java 内存模型 (JMM)                             │   │
│  │                                                                     │   │
│  │  核心目标: 定义"线程看到共享变量"的规则                                 │   │
│  │  ├─ 可见性 (Visibility) — 线程 A 的写何时对线程 B 可见                │   │
│  │  ├─ 有序性 (Ordering)   — 重排序在哪些边界内是安全的                   │   │
│  │  └─ 原子性 (Atomicity)  — 哪些操作是原子的(JMM 保证 8 字节对齐读写) │   │
│  └──────────────────────────────────────────────────────────────────┘   │
│                            │                                              │
│              ┌─────────────┼─────────────┐                               │
│              ▼             ▼             ▼                                │
│  ┌──────────────────┐ ┌──────────┐ ┌────────────┐                       │
│  │  happens-before   │ │ volatile │ │  final      │                       │
│  │  8 条规则          │ │ 内存屏障  │ │  构造函数安全 │                       │
│  │  可见性契约        │ │ DCL 修复  │ │  发布安全    │                       │
│  └──────────────────┘ └──────────┘ └────────────┘                       │
│              │             │             │                                │
│              └─────────────┼─────────────┘                                │
│                            ▼                                              │
│              ┌──────────────────────────────┐                           │
│              │  synchronized 实现机制          │                           │
│              │  ├─ MarkWord 锁状态位           │                           │
│              │  ├─ ObjectMonitor              │                           │
│              │  └─ 锁升级: 偏向 → 轻量 → 重量   │                           │
│              └──────────────────────────────┘                           │
└─────────────────────────────────────────────────────────────────────────┘

四、核心考点速记

1. happens-before 8 条规则(最快速度背下来)

#规则一句话
1程序次序规则单线程内,写在前面的代码 happens-before 后面的
2监视器锁规则unlock hb 后续 lock
3volatile 变量规则volatile 写 hb 后续 volatile 读
4传递性A hb B ∧ B hb C → A hb C
5线程启动规则start() hb 线程内所有动作
6线程终止规则线程内动作 hb join() 返回
7线程中断规则interrupt() hb 检测到中断
8对象终结规则构造函数结束 hb finalize()

2. volatile 内存屏障

volatile 写: [StoreStore] → 赋值 → [StoreLoad]    (StoreLoad 最贵!)
volatile 读: 读取 → [LoadLoad] → [LoadStore]

3. 锁升级路径

无锁 (01) ──→ 偏向锁 (01, biased=1) ──→ 轻量级锁 (00) ──→ 重量级锁 (10)

                              hashCode() 调用阻止偏向锁

4. MarkWord 锁状态位速查

状态biasedlock存储内容
无锁001hashCode、GC age
偏向锁101线程 ID、epoch、GC age
轻量锁00Lock Record 指针
重量锁10ObjectMonitor 指针
GC 标记11GC 线程使用

五、面试高频追问一览

追问关联笔记频次
JMM 是什么?为什么需要它?**JMM与happens-before**极高
happens-before 的 8 条规则?**JMM与happens-before**极高
happens-before 是时间先后关系吗?**JMM与happens-before**
volatile 的两层语义?**volatile的内存语义**极高
volatile 能保证原子性吗?**volatile的内存语义**极高
DCL 为什么需要 volatile?**volatile的内存语义**极高
final 在 JMM 中有什么特殊语义?**final的内存语义**
构造函数中 this 逸出有什么问题?**final的内存语义**
synchronized 的底层实现?**synchronized的JVM实现**极高
锁升级的过程?**锁升级过程**极高
偏向锁为什么被撤销?**锁升级过程**
轻量锁和重量锁的区别?**synchronized的JVM实现**
自适应自旋是什么?**锁升级过程**中高

📚 相关链接

  • **对象内存布局(MarkWord与Klass与实例数据)** — MarkWord 锁状态位与对象内存布局
  • **方法内联和逃逸分析** — 逃逸分析为锁消除提供基础
  • **锁消除与标量替换** — 锁消除依赖 JMM 规则和安全边界
  • **Java堆** — 堆是共享变量存储的区域
  • ← 返回 **JVM文库设计文档**

Knowledge4J — Java 知识库