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

Java高频面试之并发编程-14

hello啊,各位观众姥爷们!!!本baby今天又来报道了!哈哈哈哈哈嗝🐶

面试官:指令重排有限制没有?happens-before 又是什么?


在并发编程中,指令重排(Instruction Reordering)happens-before 原则是确保多线程程序正确性的核心机制。


一、指令重排的限制

1. 指令重排的定义

编译器或处理器为了优化性能,可能在不改变单线程执行结果的前提下,调整指令的执行顺序。例如:

int a = 1;  // 指令1
int b = 2;  // 指令2

编译器可能先执行指令2再执行指令1,因为这对单线程结果无影响。

2. 重排的限制

在多线程环境下,无限制的指令重排会导致数据不一致。因此,JMM(Java内存模型)通过 happens-before原则 限制重排,确保以下操作的顺序性:

  • 写后读:若操作A写变量,操作B读该变量,则A必须在B之前。
  • 写后写:若操作A和B都写同一变量,A必须在B之前。
  • 读后写/读:若操作A读变量,操作B写或读该变量,则需确保可见性。
3. 禁止重排的场景
  • volatile变量:对volatile变量的读写操作不能被重排。
  • 锁操作:加锁(monitorenter)和解锁(monitorexit)之间的代码不能被重排到锁外。
  • final字段:构造函数中对final字段的写入,不会被重排到构造函数外。

二、happens-before原则

1. 定义

happens-before是JMM定义的操作间的偏序关系,确保前一个操作的结果对后续操作可见。若操作A happens-before操作B,则:

  • A的执行结果对B可见。
  • A的执行顺序排在B之前。
2. 核心规则
规则描述示例
程序顺序规则单线程中,代码书写顺序的操作happens-before后续操作。int x=1; int y=x+1;x=1 happens-before y=x+1
volatile规则volatile变量的写操作happens-before后续对该变量的读操作。volatile boolean flag=false;flag=true写happens-beforeflag读。
锁规则解锁操作happens-before后续的加锁操作。synchronized(lock){...} → 解锁happens-before下一个线程的加锁。
线程启动规则线程的start()调用happens-before该线程内的任何操作。thread.start() → 线程内run()中的操作可见start()前的修改。
线程终止规则线程中的所有操作happens-before其他线程检测到该线程终止(如join()返回)。thread.join() → 主线程能看到线程内所有修改。
传递性规则若A happens-before B,且B happens-before C,则A happens-before C。用于链式操作的有序性保证。
3. 实际应用
  • 双重检查锁定(DCL)

    public class Singleton {private static volatile Singleton instance; // 必须用volatilepublic static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton(); // 禁止重排初始化与赋值}}}return instance;}
    }
    

    volatile防止指令重排,确保对象完全初始化后才赋值给instance

  • 线程间通信

    volatile boolean flag = false;
    // 线程1
    data = 42;
    flag = true; // 写操作happens-before线程2的读操作
    // 线程2
    while (!flag); // 等待flag为true
    System.out.println(data); // 确保看到data=42
    

    volatile保证线程1的写操作对线程2可见。


三、happens-before与内存屏障

1. 内存屏障的作用

JVM通过插入内存屏障(Memory Barrier)指令实现happens-before规则,限制指令重排。常见屏障类型:

  • LoadLoad:确保当前读操作前的所有读操作完成。
  • StoreStore:确保当前写操作前的所有写操作完成。
  • LoadStore:确保当前读操作后的所有写操作完成。
  • StoreLoad:确保当前写操作后的所有读/写操作完成(开销最大)。
2. volatile的实现
  • 写操作:在写volatile变量后插入StoreStoreStoreLoad屏障。
  • 读操作:在读volatile变量前插入LoadLoadLoadStore屏障。

四、总结

机制核心作用关键点
指令重排优化性能,但受限于happens-before规则。单线程结果不变,多线程需同步机制保证可见性。
happens-before定义操作间的可见性和顺序性,限制指令重排。通过程序顺序、锁、volatile等规则确保多线程正确性。
内存屏障物理实现happens-before规则,强制刷新内存和限制重排。volatile、锁等同步机制的底层依赖。

开发建议

  • 优先使用volatilesynchronized、原子类等工具显式管理同步。
  • 理解happens-before规则,避免隐式依赖指令顺序。
  • 复杂场景结合工具(如java.util.concurrent包)简化并发控制。
    在这里插入图片描述
http://www.xdnf.cn/news/344377.html

相关文章:

  • vue v-html无法解析<
  • 负载均衡算法解析(一)NGINX
  • 闪回查询和闪回表
  • es 里的Filesystem Cache 理解
  • [工具分享]欧拉角-四元数可视化工具
  • 科技成果鉴定测试有哪些内容?又有什么作用?
  • 美信监控易:网络设备智能识别与运维系统快捷配置
  • PostgreSQL 的 pg_current_logfile 函数
  • 利用session在html和MySQL实现登录
  • MySQL 8.0 OCP认证考试题库持续更新
  • 树状数组的操作问题--Python
  • SSL证书管理系统GO中文版自动申请SSL证书部署自动续期域名列表授权管理源码
  • 亚马逊推出新型仓储机器人 Vulcan:具备“触觉”但不会取代人类工人
  • V4L2应用程序开发-- 控制流程
  • Python爬虫中time.sleep()与动态加载的配合使用
  • C#串口通信
  • 国内led显示屏厂家以及售后 消费对比与选择
  • 高效文件夹迁移工具,轻松实现批量文件管理
  • CSS相对定位与绝对定位
  • 前端基础之《Vue(15)—组件通信(2)》
  • Cut video with ffmpeg
  • 创建型模式:工厂方法(Factory Method)模式
  • 最新CDGP单选题(第四章)补充
  • 力扣智慧思想小题,目录力扣.跳跃游戏(思想很重要)力扣.跳跃游戏II(还是思想)力扣.分发糖果力扣151.反转字符串中的单词力扣.轮转数组
  • cat、more和less的区别
  • 趣味编程:答案之书
  • CSS动画
  • AI视频生成的艺术:镜头语言
  • 多模态大语言模型arxiv论文略读(六十四)
  • 算法每日一题 | 入门-分支结构-Apples Prologue/苹果和虫子