欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 高考 > Java高频面试之并发编程-14

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

2025/11/9 16:20:01 来源:https://blog.csdn.net/2401_87189717/article/details/147804395  浏览:    关键词: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包)简化并发控制。
    在这里插入图片描述

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词