当前位置: 首页 > news >正文

【Java-JMM】Happens-before原则

一、什么是 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.gsyq.cn/news/29704.html

相关文章:

  • P6072 『MdOI R1』Path
  • P1601题解
  • 关于驻马店市 2025 中小学信息学竞赛的记录(入门级)(未完)
  • 游记——驻马店市2025中小学信息学竞赛(未完)
  • ABP - SqlSugar [SqlSugarModule、ISqlSugarClient、SqlSugarRepository]
  • Odoo18.0 对接 京东快递
  • 轮次检测模型 VoTurn-80M 开源,多模态融合架构;OpenAI 收购桌面助手 Sky:实时识别屏幕自然语言交互丨日报
  • SAP维护汇率的关键Tcode
  • 第4天(中等题 滑动窗口、哈希表)
  • 申威服务器安装Java11(swjdk-11u-9.ky10.sw_64.rpm)详细操作步骤(附安装包)
  • Linux下的拼音输入法 (3)
  • P2606 [ZJOI2010] 排列计数 分析
  • 实用指南:MacOS - Clang使用bits/stdc++.h - 非官方(竞赛用) - 通用方法
  • 设计模式:代码界的 “光之巨人” 养成指南(附 C++ 实战)
  • 详细介绍:17-Language Modeling with Gated Convolutional Networks
  • 算法分析--生成排列
  • 三大安全认证授权协议深度对比:OAuth、OpenID Connect与SAML
  • (简记)(自用)线段树区间拆分时间复杂度证明
  • SpringBoot整合缓存2-Redis
  • 10.24 CSP-S 模拟37 改题记录
  • NOI25D2T2
  • 数字人企业:数字人公司重点推荐与选择指南
  • 据说每邀请一位朋友加入Comet,您可以获得10刀乐奖励:D
  • 王炸!OpenAI 发布 Atlas 浏览器!!
  • 课后作业4
  • cn域名隐私保护
  • 【开题答辩全过程】以 M11289生鲜商城为例,具备答辩的问题和答案
  • Linux手动安装最新版 CMake
  • 2025年新疆喀纳斯旅游服务权威推荐榜单:新疆/阿勒泰/禾木深度游旅行社综合评测
  • 2025 OSCAR丨与创新者同频!Apache RocketMQ 邀您共赴开源之约