0

0

什么是Happens-Before原则_JMM提供的八条先行发生规则详解

P粉602998670

P粉602998670

发布时间:2026-02-14 16:45:11

|

794人浏览过

|

来源于php中文网

原创

happens-before 是 java 内存模型中保障多线程下变量可见性与有序性的唯一硬性依据,它定义操作 a 对 b 的结果可见且不重排序,但不保证原子性、不等价于时间先后、不跨线程自动传递。

什么是happens-before原则_jmm提供的八条先行发生规则详解

Happens-Before 原则不是语法糖,也不是 JVM 的优化开关——它是 Java 内存模型(JMM)里唯一能让你在多线程下「放心读到最新值」的硬性依据。 没有它,就算你用了 synchronizedvolatileLock,编译器和 CPU 仍可能重排序、缓存不一致、读到过期数据。

什么是 happens-before?别被术语吓住,它就两条铁律

它定义的是「操作 A 是否对操作 B 可见」:如果 A happens-before B,那么 A 的结果(比如变量写入)一定对 B 可见,且 A 不会重排序到 B 之后。

  • 它不等于「时间上先发生」——System.currentTimeMillis() 返回的时间戳不能用来判断 happens-before
  • 它不传递给无关线程——线程 T1 中 A → B,T2 中 C → D,但 T1 和 T2 无同步关系,则 A 对 D 不保证可见
  • 它只在 JMM 层面起作用,和操作系统调度、CPU 核心缓存刷新时机无关,但依赖 JVM 对这些底层行为的建模

八条规则里真正常踩坑的只有这三条

官方说八条,但日常开发中,90% 的问题出在以下三个场景,其余多是组合推导或边界情况。

Waymark
Waymark

Waymark是一个视频制作工具,帮助企业快速轻松地制作高影响力的广告。

下载
  • synchronized 锁释放 happens-before 同一锁的获取:注意「同一把锁」——obj1 上的 synchronized 释放,对 obj2 的获取无效
  • volatile 写 happens-before 后续任意线程对该 volatile 变量的读:但对非 volatile 字段无扩散效应(常见误以为「写了 volatile 就等于 flush 了整个缓存行」)
  • 线程 start() happens-before 该线程的任意动作;线程所有动作 happens-before 其 join() 返回:注意 join() 是阻塞调用,不是「线程结束瞬间」生效——没等 join() 就去读共享变量,照样可能读到旧值

为什么加了 volatile 还读不到新值?检查这三件事

这是最典型的「以为满足 happens-before,其实链断了」。

  • 确认读写的是同一个 volatile 变量名——flag 是 volatile,但代码里读的是 flagCopy = flag,再读 flagCopy,那就完全不参与 happens-before 链
  • 确认没有绕过 volatile 的间接引用——比如 volatile List<integer> list</integer>,然后执行 list.add(1),add 本身不具 volatile 语义,list 引用虽可见,但内部状态变更不可见
  • 确认没有 JIT 优化干扰——极少数情况下(如空循环 + volatile 读),JIT 可能将读提升到循环外(可通过 -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly 观察,但生产环境几乎不用深究)

happens-before 不是万能锁,别指望它替代同步逻辑

它只管「可见性」和「有序性」,不管「原子性」。比如 i++(读-改-写)即使 i 是 volatile,依然会丢失更新。

  • volatile int counter + 多线程 counter++ → 结果必然小于预期,因为 counter++ 不是原子操作,happens-before 只保证每次读到最新值,不保证两次读之间没被别人改过
  • 想靠 volatile 实现状态机流转(如 state = INIT → RUNNING → DONE)可以,但一旦涉及「检查后执行」(if state == RUNNING then doWork()),就必须配合 synchronizedAtomicInteger.compareAndSet
  • JMM 不承诺「全局单调时钟」——两个线程各自观察到的 happens-before 关系可能不一致(虽然实际极少影响业务),所以不要用它做分布式序号生成

真正难的从来不是背八条规则,而是每次写共享变量前,心里得清楚:这条读/写操作,落在哪条 happens-before 链上?链的起点和终点是否真被同一线程或同步机制覆盖?漏掉一个环节,就回到「看似正确、实则竞态」的状态。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
什么是分布式
什么是分布式

分布式是一种计算和数据处理的方式,将计算任务或数据分散到多个计算机或节点中进行处理。本专题为大家提供分布式相关的文章、下载、课程内容,供大家免费下载体验。

388

2023.08.11

分布式和微服务的区别
分布式和微服务的区别

分布式和微服务的区别在定义和概念、设计思想、粒度和复杂性、服务边界和自治性、技术栈和部署方式等。本专题为大家提供分布式和微服务相关的文章、下载、课程内容,供大家免费下载体验。

245

2023.10.07

if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

810

2023.08.22

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

730

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

564

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

213

2025.08.29

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

206

2025.08.29

c++中volatile关键字的作用
c++中volatile关键字的作用

本专题整合了c++中volatile关键字的相关内容,阅读专题下面的文章了解更多详细内容。

70

2025.10.23

pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法
pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法

本专题系统整理pixiv网页版官网入口及登录访问方式,涵盖官网登录页面直达路径、在线阅读入口及快速进入方法说明,帮助用户高效找到pixiv官方网站,实现便捷、安全的网页端浏览与账号登录体验。

23

2026.02.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Java 教程
Java 教程

共578课时 | 65.4万人学习

国外Web开发全栈课程全集
国外Web开发全栈课程全集

共12课时 | 1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号