volatile写操作触发StoreStore和StoreLoad屏障:前者确保其前所有普通写不重排到之后,后者阻止其后任意读操作提前执行;volatile读操作插入LoadLoad和LoadStore屏障,分别保证前置读完成和后续写不提前。

Java 内存模型(JMM)不直接暴露内存屏障给开发者,而是通过 volatile、synchronized 和 final 等语义,由 JVM 在编译和运行时自动插入对应类型的内存屏障指令,从而禁止特定方向的指令重排序。
volatile 读写触发的屏障组合
对 volatile 变量的每次读或写,JVM 会在生成的汇编代码中插入一组硬件级内存屏障,其语义由 Java 规范定义,具体实现则依赖 CPU 架构:
-
volatile 写操作:插入 StoreStore + StoreLoad 屏障
→ 确保该写之前的所有普通写操作不会被重排到它之后;
→ 同时阻止它之后的读操作被提前执行(防止后续读“看到”未完成的写)。 -
volatile 读操作:插入 LoadLoad + LoadStore 屏障
→ 确保该读之前的所有普通读操作已完成;
→ 同时阻止它之后的写操作被重排到它前面(保障读结果对后续写可见)。
内存屏障如何起作用
内存屏障是 CPU 提供的特殊指令(如 x86 的 lock addl 或 ARM 的 dmb ish),它有两个核心效果:
- 禁止重排序:屏障两侧的某些类型访存指令(读/写)不能跨屏障交换顺序;
- 强制刷新缓存:在多核环境下,触发缓存一致性协议(如 MESI),使本地修改对其他核心可见。
例如,在双检锁单例中:instance = new Singleton() 若 instance 是 volatile 字段,JVM 就会确保对象构造完成(包括所有字段初始化)后再写入 instance,避免其他线程拿到半初始化的对象——这正是 StoreLoad 屏障兜底的结果。
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
屏障只约束相关操作,不保证全局顺序
内存屏障的作用范围不是整个方法或线程,而是严格绑定于 volatile 变量的读写,并仅对与之存在 happens-before 关系的操作生效:
- 若
a = 1; flag = true;中flag是 volatile,则a = 1不会被重排到flag = true之后; - 但
a和b都是非 volatile 变量时,它们之间的读写顺序无法靠 volatile 保障; - 复合操作(如
count++)仍需synchronized或AtomicInteger,因为屏障不提供原子性。
编译器层面也受约束
除了硬件屏障,JMM 还要求编译器(含 JIT)遵守重排序限制:
- 不允许把 volatile 写之前的普通读写,重排到该写之后;
- 不允许把 volatile 读之后的普通读写,重排到该读之前;
- 但 volatile 变量自身的多次读写之间,或与其他 volatile 变量之间的相对顺序,仍需靠程序逻辑或 happens-before 显式建立。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










