Java内存模型(JMM)定义了多线程环境下共享变量的可见性、原子性和有序性三大核心特性:可见性指线程修改对其他线程是否立即可见,依赖volatile、synchronized等保障;原子性指操作不可分割,基本类型单次读写是原子的,复合操作需同步机制;有序性指禁止指令重排,通过volatile内存屏障和happens-before规则约束。

Java 中的可见性、原子性和有序性,是理解多线程安全最核心的三个基础概念。它们不是语法糖,而是 Java 内存模型(JMM)对共享变量在多线程环境下行为的约束规则。
可见性:一个线程改了,别的线程能不能马上看到?
每个线程都有自己的工作内存(比如 CPU 缓存),读写共享变量时可能不直接操作主内存。这就导致:线程 A 修改了 flag = false,但没及时刷回主内存;线程 B 一直从自己缓存里读到旧值 true,死循环停不下来。
- volatile:强制每次读都从主内存取,每次写都立刻刷到主内存,解决可见性
- synchronized / Lock:解锁前把所有修改写回主内存,加锁时强制从主内存读最新值
- final:对象构造完成那一刻,其 final 字段对其他线程可见
原子性:一个动作是不是“不可拆分”的最小单位?
像 i++ 看似一行,实际是“读 i → 加 1 → 写回 i”三步。两个线程同时执行,可能都读到 0,都算出 1,最后只写入一次,结果变成 1 而不是 2 —— 这就是原子性被破坏。
- 基本类型(int、boolean 等)的单次读/写是原子的(long/double 在 64 位 JVM 上通常也是)
- volatile 不能保证复合操作(如 i++)的原子性,只保单次读写
- 要用 synchronized、ReentrantLock 或 AtomicInteger 等原子类来包裹非原子操作
有序性:代码写的顺序,是不是真的按这个顺序执行?
为了性能,编译器和 CPU 可能重排指令。比如创建对象:
1. 分配内存
2. 初始化对象
3. 把引用赋值给变量
重排成 1→3→2 后,另一个线程可能拿到一个“已赋值但未初始化”的引用,引发空指针或异常状态。
立即学习“Java免费学习笔记(深入)”;
- volatile 会插入内存屏障,禁止其前后指令重排序
- synchronized 块内指令不会被重排到块外,且加锁/解锁本身构成 happens-before 关系
- happens-before 是 JMM 定义的逻辑顺序规则,比如“解锁操作 happens-before 后续加锁操作”,它比物理执行顺序更关键


















