jmm通过happens-before原则保障有序性而非禁止重排序;它定义8条内置规则(如程序顺序、volatile变量、锁规则等)建立操作间逻辑依赖,确保结果可见性与执行约束。

Java 内存模型(JMM)不靠强制按代码顺序执行来保证有序性,而是通过 happens-before 原则 划定操作间逻辑依赖的边界,让重排序“有约束地发生”,既保障正确性,又保留性能优化空间。
happens-before 是有序性的核心契约
它不是时间先后关系,而是一种语义保证:如果操作 A happens-before 操作 B,那么 A 的结果(如变量写入)对 B 一定可见,且 JVM 和 CPU 的重排序不能破坏这个逻辑链。没有这条链,编译器可能把 x = 1 和 flag = true 调换顺序,线程 B 就可能看到 flag == true 却读到 x == 0。
八条内置规则提供默认有序性保障
这些规则是语言层面自动生效的,无需手动加锁:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
-
程序顺序规则:单线程内,前一条语句的任意操作 happens-before 后一条语句的任意操作。例如
a = 1; b = a + 1;中,a的写一定 happens-beforeb的读。 -
volatile 变量规则:对 volatile 变量的写 happens-before 后续对该变量的读。更重要的是,该写之前所有普通变量的修改(如
data = 42),也会一并对其后的 volatile 读可见。 - 监视器锁规则:一个线程释放锁(unlock)happens-before 另一线程获取同一把锁(lock)。因此临界区内的写,在加锁后能被安全读取。
-
线程启动/终止规则:主线程调用
thread.start()前的所有操作,对新线程可见;thread.join()返回后,子线程所有操作结果对主线程可见。
有序性 ≠ 禁止重排序,而是控制重排序范围
JMM 允许重排序,但只允许在不破坏已建立的 happens-before 关系的前提下进行。比如:
- volatile 写前后,编译器不能把普通写“挪到” volatile 写之后;
- synchronized 块退出时,会插入内存屏障,阻止工作内存中变量的写被延迟刷回主内存;
- final 字段的初始化完成 happens-before 构造方法结束,保证其他线程看到对象时,final 字段已正确赋值。
不正确同步会导致有序性失效
当两个线程分别读写同一个非 volatile、非同步的变量,且无 happens-before 链时,JMM 不做任何保证。此时可能出现:
- 线程 A 修改了
ready = true和data = 42,但线程 B 读到ready == true却看到data == 0; - 编译器把
data = 42重排到ready = true之后,CPU 缓存未及时刷新,导致 B 看到“半初始化”状态。
不复杂但容易忽略
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










