传递性规则是Happens-Before关系的逻辑链路基础:若A→B且B→C,则A→C;它不创造新关系,仅串联已有规则支撑的段落,从而间接保障远端操作的内存可见性。

传递性规则是 happens-before 关系中让多个操作“连起来”的关键机制——它不直接建立两个操作之间的可见性,而是把已有的 happens-before 链接串成更长的逻辑链条,从而间接保证远端操作间的内存可见性。
传递性怎么起作用?
如果操作 A happens-before 操作 B,且操作 B happens-before 操作 C,那么 Java 内存模型(JMM)就保证:A happens-before C。这个结论不需要额外同步,也不依赖时间先后,只依赖已有规则推导出的两个前提。
重点在于:A→B 和 B→C 这两段关系必须各自满足某条 happens-before 规则(比如程序顺序、锁规则或 volatile 规则),传递性只是把它们“拼接”起来,形成 A→C 的可见性担保。
常见串联场景举例
以下例子都基于真实编码模式,展示传递性如何实际生效:
-
线程启动 + 程序顺序 → 跨线程可见:主线程中先设置
data = 42,再调用t.start();子线程里读data。 → 主线程中data = 42happens-beforet.start()(启动规则); →t.start()happens-before 子线程第一条语句(启动规则); → 由传递性,data = 42happens-before 子线程读data,所以能看见 42。 -
解锁 + 锁定 + 程序顺序 → 临界区接力:线程 A 在 synchronized 块内写
flag = true后释放锁;线程 B 获取同一把锁后读flag。 → A 的 unlock happens-before B 的 lock(锁规则); → B 的 lock happens-before 其后读flag(程序顺序规则); → 传递得:A 写flag的结果对 B 的读可见。 -
volatile 写 + 程序顺序 + volatile 读 → 多步扩散:线程 A 写 volatile 变量
ready = true前,先设value = 100;线程 B 读到ready == true后访问value。 →value = 100happens-beforeready = true(同一线程程序顺序); →ready = truehappens-before 线程 B 读ready(volatile 规则); → 传递得:value = 100happens-before B 读value,B 必能看到 100。
传递性不是万能的——它的边界在哪?
传递性只在“有明确中间点”且“每一段都有规则支撑”时才成立。以下情况无法传递:
- 两个操作之间没有共同的操作作为桥梁(比如 A→?→C,但找不到那个 ?);
- 其中某一段关系并不存在(例如跨线程无同步地读写普通变量,A 和 B 之间无任何 happens-before);
- 试图用不同锁、不同 volatile 变量强行“跨链”(如 A 写 vol1 → B 读 vol1,B 写 vol2 → C 读 vol2,不能推出 A→C)。
换句话说:传递性不创造新关系,只延伸已有关系。它像一座桥,但桥墩必须由其他规则(锁、volatile、start 等)稳稳打下。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











