【Java-JMM】Happens-before原则

news/2025/10/24 21:06:14/文章来源:https://www.cnblogs.com/haof31/p/19164222

一、什么是 Happens-before 原则

Happens-before 原则是 Java 内存模型(JMM)的核心概念,用于定义多线程环境下操作之间的内存可见性关系。

核心理解:如果操作 A happens-before 操作 B,那么 A 的执行结果对 B 可见。这个原则主要解决了 Java 并发编程中的两个关键问题:

  • 可见性问题:由 CPU 缓存引起
  • 有序性问题:由编译器优化和指令重排引起

二、Happens-before 的具体规则

1. 程序顺序性规则

在单线程中,按照程序代码顺序,前面的操作 happens-before 后面的操作。

关键点

  • 有依赖关系:操作间存在数据依赖时,顺序不可重排
  • 无依赖关系:操作间无数据依赖时,可以重排序,但要保证单线程执行结果不变
int a = 1;     // 操作A
int b = 2;     // 操作B(与A无依赖,可重排)
int c = a + 1; // 操作C(依赖A,必须在A之后)
int d = b * 2; // 操作D(依赖B,必须在B之后)// 可能的执行顺序:
// ✓ A → B → C → D(原始顺序)
// ✓ B → A → C → D(B与A无依赖,可交换)
// ✗ C → A → B → D(C依赖A,不能在A之前)

2. volatile 变量规则

对 volatile 变量的写操作 happens-before 后续对该变量的读操作。

volatile int flag = 0;// 线程A
flag = 1;  // 写操作// 线程B
if (flag == 1) {  // 读操作// 能看到线程A的写入
}

3. 传递性规则

如果 A happens-before B,且 B happens-before C,那么 A happens-before C。

4. 锁规则(Monitor Lock Rule)

对一个锁的解锁操作 happens-before 后续对这个锁的加锁操作。

synchronized (lock) {// 临界区代码
}  // 解锁// 其他线程
synchronized (lock) {  // 加锁// 能看到前一个线程在临界区的所有操作
}

5. 线程启动规则

线程 A 中调用线程 B 的 start() 方法之前的所有操作,happens-before 线程 B 中的任意操作。

6. 线程终止规则

线程 B 中的所有操作 happens-before 线程 A 中调用 B.join() 方法成功返回后的操作。

public class VisibilityDemo {static int var = 0;public static void main(String[] args) throws InterruptedException {// 主线程操作var = 10;  // ① 主线程修改Thread B = new Thread(() -> {// 子线程B能看到①的修改(线程启动规则)var = 66;  // ② 子线程修改});B.start();  // 启动子线程B.join();   // 等待子线程结束// ③ 主线程能看到②的修改(线程终止规则)System.out.println(var);  // 输出:66}
}

执行流程:

  • 根据线程启动规则:主线程的 var = 10 happens-before 子线程 B 的所有操作
  • 根据线程终止规则:子线程 B 的 var = 66 happens-before 主线程 join() 之后的操作
  • 因此主线程最终能看到 var 的值为 66

7. final 字段规则

在构造函数中对 final 字段的写入,happens-before 其他线程对该对象的 final 字段的读取。

public class FinalExample {private final int value;public FinalExample(int value) {this.value = value;  // 构造函数中的写入}// 其他线程读取时,保证能看到构造函数中的赋值public int getValue() {return value;}
}

三、总结

Happens-before 原则是 Java 并发编程的基石,它通过定义操作间的可见性关系,让开发者能够在不了解底层硬件细节的情况下,编写正确的并发程序。掌握这些规则,是写出线程安全代码的关键。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/945665.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

P6072 『MdOI R1』Path

给定一颗无根树 \(|T|\)。 求两条点不相交的路径,使得两条路径上边权的异或和加起来最大。 \[|T| \le 3\times 10^4 \] 这是一个经典 trick: 对于求两条点不相交路径,我们可以枚举点 \(x\),使得其中一条在 \(x\) 的…

P1601题解

题意 就是A+B,相信大家都能理解,对于Python来说很简单,对C++崽就不友好了 解析 下面提供一种解法(代码中的BitInt500这个类,别问我那个什么int128函数,不顶事): 1.创建数组 2.从字符串构造大型整数 3.大整数加法…

10-23 好题选讲总结

10-23 好题选讲总结 P13779 「o.OI R2」试机题 - 洛谷 注意特殊的数据范围。 \(K=2\) 就是黑白染色,然后检查黑白点数是否相等,\(K=3\) 可以 \(O(n^2)\) DP 设 \(f_{i,j,0/1}\) 表示子树内选了 \(j\) 个与 \(i\) 颜色…

关于驻马店市 2025 中小学信息学竞赛的记录(入门级)(未完)

全网好像都没有关于这个神秘竞赛的内容。 包括它的神秘举办方:驻马店市计算机学会。ZCF? 因此我决定写一篇记录,同时公布关于这个比赛的 几乎 所有信息。————题记By CasKPART 1. 赛前通知 本人是驻马店第*初级中…

关于Markdown的使用

因为在使用Markdown来编写博客,这里将会给出一些Markdown的笔记来方便后续使用。 标题采用#来表示几级标题,例如#为一级,##为二级。 这是一个一级标题 这是一个二级标题 字体采用*或者_来表示,一个表示斜体,两个表…

自定义Spring Cloud LoadBalancer实践

Spring Cloud负载均衡概述 在不同的Spring Cloud版本中,采用了不同的负载均衡组件。 具体来说,在Spring Cloud 2020.0版本之前,默认负载均衡器为Netflix推出的Ribbon,自Spring Cloud 2020.0版本起,Ribbon已经被标…

游记——驻马店市2025中小学信息学竞赛(未完)

全网好像都没有关于这个神秘竞赛的内容。 包括它的神秘举办方:驻马店市计算机学会。ZCF? 因此我决定写一篇游记,同时公布关于这个比赛的 几乎 所有信息。————题记By CasKPART 1. 赛前通知 以下是比赛前老师发给…

SAP折旧模拟超过1000条资产dump问题及解决

通过如下Tcode做资产折旧模拟时,发现如果超出100条资产系统会dump. S_ALR_87012936 - 折旧模拟 AR18N - 折旧模拟(新)解决办法: note:3396352 - Performance issues in Asset reporting or archiving, 可以配置单…

ABP - SqlSugar [SqlSugarModule、ISqlSugarClient、SqlSugarRepository]

SqlSugar ORM 集成 核心辅助类:SqlSugarModule:SqlSugar集成模块(需手动引入社区包)。 ISqlSugarClient:SqlSugar核心客户端。 SqlSugarRepository<T>:基于SqlSugar的仓储实现。你关注到了ABP与SqlSugar O…

Odoo18.0 对接 京东快递

京东快递 本章我们来看一下如何使用我们欧姆网络科技的京东快递插件来完成Odoo与京东快递的对接。 前期准备 首先我们要先在京东快递的开放平台注册一个商家[自研商家],并完成认证签约。入驻之后我们需要拿到如下参数…

Matplotlib常见画图工具

View PostMatplotlib常见画图工具一、Matplotlib核心基础 在开始绘图前,需掌握以下基础框架,几乎所有图表都基于此扩展:点击查看代码 # 1. 导入库 import matplotlib.pyplot as plt import numpy as np # 用于生成…

[python] 代码性能分析工具line_profiler使用指北

代码分析能够评估各部分代码的时间消耗,即进行时间复杂度分析。通过这一过程,我们可以识别影响整体运行效率的关键部分,从而更高效地利用底层计算资源。此外,代码分析也可用于评估内存使用情况,即空间复杂度,以优…

react的diff算法

这个算法用来比较虚拟dom和真实dom,从而最小化真实dom的更新 本质上是对两颗Fiber树的对比 (在Vue中是对旧VDOM树与新VDOM树的对比) 在不剪枝的情况下,时间复杂度接近O(n^3)基于最长公共子序列 (LCS) 的朴素计算为…

LLM学习记录DAY11

📘今日学习总结 tokenization分词算法 BPE分词(Byte-Pair Encoding)BPE 算法从一组基本符号(例如字母和边界字符)开始,迭代地寻找语料库中的两个相邻词元,并将它们替换为新的词元,这一过程被称为合并。 合并的…

ABP - 当前用户 [ICurrentUser、CurrentUser]

当前用户(Current User) 核心辅助类:ICurrentUser:获取当前登录用户信息(ID、用户名、角色等)。 CurrentUser:静态快捷访问(需在请求上下文内)。在ABP框架中,ICurrentUser和CurrentUser用于获取当前登录用户…

轮次检测模型 VoTurn-80M 开源,多模态融合架构;OpenAI 收购桌面助手 Sky:实时识别屏幕自然语言交互丨日报

开发者朋友们大家好:这里是 「RTE 开发者日报」,每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE(Real-Time Engagement) 领域内「有话题的技术」、「有亮点的产品」、「有思考的文章」、「有态度…

ABP - 依赖注入和属性注入

一、依赖注入(Dependency Injection) 核心辅助类:IServiceCollection:扩展方法(如AddTransient、AddScoped)。 DependencyAttribute:标记注入生命周期(Transient/Scoped/Singleton)。 IIocResolver:手动解析…

ABP vNext 框架功能模块 - 依赖注入和属性注入

一、依赖注入(Dependency Injection) 核心辅助类:IServiceCollection:扩展方法(如AddTransient、AddScoped)。 DependencyAttribute:标记注入生命周期(Transient/Scoped/Singleton)。 IIocResolver:手动解析…

SAP维护汇率的关键Tcode

Tcode: OB08 维护汇率Tcode:OBBS 维护汇率的折算比率☆ No matter how much you change, you still have to pay the price for the things youve done.

幂函数

观察幂函数图像结论: 所有的幂函数都过1,1点,幂函数在第一象限必有图像。 a为负数时,不过0,0点,其余都有0,0点。 一、画函数用结论,a<0,单调递减,a>0,单调递增。 二、0<a<1之间,增的缓,a>1,…