0

0

Java并发中的Happens-Before原则是什么_内存模型有序性保证

P粉602998670

P粉602998670

发布时间:2026-03-08 09:47:27

|

683人浏览过

|

来源于php中文网

原创

java并发中的happens-before原则是什么_内存模型有序性保证

happens-before 是什么:不是执行顺序,而是可见性契约

它不是说「A 一定在 B 前面 CPU 执行」,而是向程序员承诺:如果 A happens-before B,那么 A 对共享变量的修改,对 B 一定是可见的;且 B 不能看到 A 之前某个中间态(比如只写了一半的 long 值)。这个保证由 JVM 在编译期插内存屏障、运行时配合 CPU 指令(如 lock xchgmfence)共同实现。

  • 常见误解:把 happens-before 当作「时间先后」——错。两个操作即使 A 在时钟上晚于 B,只要满足规则(比如 volatile 写后读),仍可构成 happens-before
  • 真正起作用的是规则链:单靠一个 volatile 读写不够,得靠传递性串起整个逻辑路径
  • as-if-serial 只管单线程;happens-before 是唯一跨线程提供语义保障的机制

哪些场景天然成立 happens-before 关系

不用加锁、不用 synchronized,JMM 就已为你埋好安全边界。但必须严格匹配条件,漏掉任一细节就失效。

  • 程序顺序规则:同一线程内,x = 1 happens-before y = x + 1 —— 但若 y = x + 1 被重排序到 x = 1 前(无数据依赖时),JVM 仍可优化,只要最终结果等价;而 happens-before 保证的是「B 能看到 A 的结果」,不是禁止重排本身
  • volatile 变量规则:对 flag(声明为 volatile boolean flag)的写,happens-before 后续任意线程对该 flag 的读。注意「后续」指时钟时间上之后,且该读必须发生在写之后(否则可能读到旧值)
  • 监视器锁规则:线程 A 执行 unlock(),happens-before 线程 B 后续对同一把锁的 lock() —— 这就是为什么 synchronized 块退出后,临界区修改对下一个获取锁的线程可见
  • 线程启动/终止规则t.start() happens-before t 中第一个动作;t 最后一个动作 happens-before 其他线程中 t.join() 返回 —— 所以你在 join() 后读共享变量是安全的

为什么 volatile 不能替代 synchronized

因为 happens-before 链不完整。volatile 只能保单个变量的写→读可见性,无法保证复合操作的原子性或多个变量间的约束关系。

Clipfly
Clipfly

一站式AI视频生成和编辑平台,提供多种AI视频处理、AI图像处理工具。

下载
  • 典型翻车现场:volatile int counter; + counter++ —— 读、改、写三步不构成原子操作,其他线程可能在「读完 counter=5」和「写回 counter=6」之间插入自己的写,导致丢失更新
  • 再比如双检锁单例:if (instance == null) { synchronized(...) { if (instance == null) instance = new Singleton(); } },若 instance 不是 volatile,new 操作可能被重排序为「分配内存→写引用→初始化对象」,导致其他线程拿到未初始化完成的对象引用
  • volatile 提供的是「写后读」的定向通道,synchronized 提供的是「进入前清空本地内存 + 退出时刷回主存」的全量同步

调试 happens-before 失效的常见线索

现象往往隐蔽:偶尔出错、压测才暴露、换个 CPU 架构就崩。别急着加锁,先看是否破坏了规则前提。

立即学习Java免费学习笔记(深入)”;

  • 看到 Thread#isAlive() 返回 false 后仍读到旧值?检查是否依赖了「线程终止规则」——但你没调用 join(),只是轮询 isAlive(),这不触发 happens-before
  • AtomicInteger 但结果不一致?确认是否混用了非原子操作:比如 ai.get() + 1ai.set(),这不是 CAS,也不受 happens-before 保护
  • 日志里发现变量值「跳变」或「回退」(比如从 2 变成 1)?大概率是缺少 volatile / 锁,导致线程看到不同缓存副本,JMM 不保证这种读的顺序一致性
  • 在 Lambda 或匿名内部类里访问外部局部变量,又在线程间共享?Java 要求该变量是「effectively final」,否则编译不过——这是编译器帮你守住程序顺序规则的第一道防线

最易被忽略的一点:happens-before 是偏序关系,不是全序。两个操作如果没有规则覆盖,也没有传递链连接,那它们就是并发的,JVM 和 CPU 都可以自由重排。别指望「看起来应该先发生」就能得到保证——代码里没写明规则,就等于没发生。

热门AI工具

更多
DeepSeek
DeepSeek

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

豆包大模型
豆包大模型

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

通义千问
通义千问

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

腾讯元宝
腾讯元宝

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

文心一言
文心一言

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

讯飞写作
讯飞写作

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

即梦AI
即梦AI

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

ChatGPT
ChatGPT

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

相关专题

更多
java中boolean的用法
java中boolean的用法

在Java中,boolean是一种基本数据类型,它只有两个可能的值:true和false。boolean类型经常用于条件测试,比如进行比较或者检查某个条件是否满足。想了解更多java中boolean的相关内容,可以阅读本专题下面的文章。

366

2023.11.13

java boolean类型
java boolean类型

本专题整合了java中boolean类型相关教程,阅读专题下面的文章了解更多详细内容。

42

2025.11.30

c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

252

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

1049

2024.03.01

if什么意思
if什么意思

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

846

2023.08.22

string转int
string转int

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

970

2023.08.02

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

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

605

2024.08.29

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

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

294

2025.08.29

JavaScript浏览器渲染机制与前端性能优化实践
JavaScript浏览器渲染机制与前端性能优化实践

本专题围绕 JavaScript 在浏览器中的执行与渲染机制展开,系统讲解 DOM 构建、CSSOM 解析、重排与重绘原理,以及关键渲染路径优化方法。内容涵盖事件循环机制、异步任务调度、资源加载优化、代码拆分与懒加载等性能优化策略。通过真实前端项目案例,帮助开发者理解浏览器底层工作原理,并掌握提升网页加载速度与交互体验的实用技巧。

23

2026.03.06

热门下载

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

精品课程

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

共23课时 | 4.2万人学习

C# 教程
C# 教程

共94课时 | 10.8万人学习

Java 教程
Java 教程

共578课时 | 78.3万人学习

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

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