volatile变量读写本身不直接体现传递性,而是通过volatile规则、程序顺序规则和传递性规则协同建立happens-before关系:volatile写happens-before后续任意线程对该变量的读;单线程内程序顺序构成happens-before链;借助传递性将普通操作与volatile操作连接,从而保证跨线程可见性。

volatile 变量的读写本身不直接体现“传递性”,而是通过 volatile 规则 + 程序顺序规则 + 传递性规则 三者协同,让原本无直接关系的两个普通操作建立起 happens-before 关系,从而保证可见性。
volatile 写与后续读之间存在 happens-before
这是最基础的一环。对一个 volatile 变量的写操作,happens-before 于之后任意线程对该变量的读操作。这不是时间先后,而是一种语义约束:JMM 保证,读操作一定能看到该写操作(及其之前所有对共享变量的修改)的结果。
- 例如:线程 A 执行
flag = true(volatile 写),线程 B 后续执行if (flag)(volatile 读),那么 A 的写就 happens-before B 的读。 - 这个关系由 JMM 显式规定,是 volatile 语义的核心支撑。
程序顺序规则把 volatile 前后操作串起来
在单个线程内,代码顺序就是 happens-before 顺序。这意味着 volatile 写之前的其他操作,也 happens-before 这次写;volatile 读之后的其他操作,则 happens-after 这次读。
- 线程 A 中:
i = 2;→flag = true;,则i = 2happens-beforeflag = true(程序顺序)。 - 线程 B 中:
if (flag)→System.out.println(i);,则if (flag)happens-beforeprintln(i)(程序顺序)。
传递性规则完成关键“桥接”
正是靠传递性,把 A 中的普通写、A 的 volatile 写、B 的 volatile 读、B 中的普通读,连成一条链:
立即学习“Java免费学习笔记(深入)”;
- A 中
i = 2happens-beforeflag = true(程序顺序) -
flag = truehappens-beforeif (flag)(volatile 规则) -
if (flag)happens-beforeprintln(i)(程序顺序) - 因此,
i = 2happens-beforeprintln(i)(传递性)
这就解释了为什么 B 线程能安全读到 i == 2 —— 不是因为 volatile 修饰了 i,而是 volatile flag 的读写充当了“同步点”,把 i 的写和读通过 happens-before 链传递关联起来了。
注意:传递性不等于自动传播
传递性只在明确满足前驱关系时生效。如果 B 在读 flag 之前,A 还没写 flag,或者 B 的读发生在 A 写之前(逻辑上或实际执行上),那整个链就断了,i 的值对 B 就不可见。
- volatile 不保证“实时”或“立即”,只保证一旦读到了新值,它前面的所有写都已对当前线程可见。
- 没有 volatile 或锁等同步机制,仅靠代码位置无法建立跨线程的 happens-before。


















