面试官: 有了解过指令重排吗,什么是happens-before

简介: 面试官: 有了解过指令重排吗,什么是happens-before

前言

目前正在出一个Java多线程专题长期系列教程,从入门到进阶含源码解读, 篇幅会较多, 喜欢的话,给个关注❤️ ~ 本篇内容篇纯理论一点


重排序

首先,什么是重排序❓计算机在执行过程中,为了提高性能,会对编译器和编译器做指令重排


这么做为啥可以提高性能呢❓


我们知道计算机在执行的时候都是一个个指令去执行,不同的指令可能操作的硬件不一样,在执行的过程中可能会产生中断,打个比方,两个指令a和b他们操作的东西各不相同,如果加载a的时候停顿了,b就加载不到,但是实际上它们互补影响,我也可以先加载b在加载a,所以指令重排是减少停顿的一种方法,这样大大提高了效率。


指令重排的方式

指令重排一般分为以下三种

  • 编译器优化 重新安排语句的执行顺序
  • 指令并行重排 利用指令级并行技术将多个指令并行执行,如果指令之前没有数据依赖,处理器可以改变对应机器指令的执行顺序
  • 内存系统重排 由于处理使用缓存和读写缓冲区,所以它们是乱序的


指令重排可以保证串行语义一致,但是没有义务保证多线程间的语义也一致**。所以在多线程下,指令重排序可能会导致一些问题


顺序一致性模型

顺序一致性模型是一个理论参考模型,内存模型在设计的时候都会以顺序一致性内存模型作为参考。


数据竞争

我们知道在多线程情况下,同时读写一个变量会导致结果的不确定性,这就存在了数据竞争,相反的如果线程在同步情况下,就不存在数据竞争。


JMM对于同步的多线程情况下,程序执行可以保证顺序一致性,同步包括了使用volatilefinalsynchronized等关键字来实现多线程下的同步,这里的前提正确使用它们,如果使用不当,就不能保证


什么是顺序一致性模型

我们在上节给大家讲了Java的内存模型,提到了内存可见性的概念,顺序一致性模型它的最终目的就是保证内存的可见性。


它主要有两大特性:

  • 一个线程中的所有操作必须按照程序的顺序(代码顺序)来执行。
  • 不管线程是否同步,所有线程保持单一的执行顺序并且可见,且是原子性


JMM中同步的顺序一致性

在JMM中,临界区(同步方法或同步块)的代码可以发生重排,但对其它线程是无感知的,这样既提高了执行效率又不影响最终结果


JMM中未同步的顺序一致性

  • JMM没有保证未同步程序的执行结果与该程序在顺序一致性中执行结果一致
  • JMM不保证单线程内的操作会按程序的顺序执行(因为指令重排)
  • JMM不保证所有线程能看到一致的操作执行顺序(因为不能保证所以操作立即可见)
  • JMM不保证对64位的long型和double型变量的写操作具有原子性


什么是happens-before

JMM提供了happens-before规则(JSR-133规范), 开发者可以遵循这种规范编写程序,可以保证程序在JMM中具有强的内存可见性。JMM使用happens-before的概念来定制两个操作之间的执行顺序。这两个操作可以在一个线程以内,也可以是不同的线程之间。

因此,JMM可以通过happens-before关系向程序员提供跨线程的内存可见性保证。


happens-before关系的定义如下:

  1. 如果一个操作happens-before另一个操作,那么第一个操作的执行结果将对第二个操作可见,而且第一个操作的执行顺序排在第二个操作之前。
  2. 两个操作之间存在happens-before关系,并不意味着Java平台的具体实现必须要按照happens-before关系指定的顺序来执行。如果重排序之后的执行结果,与按happens-before关系来执行的结果一致,那么JMM也允许这样的重排序。


总之,如果操作A happens-before操作B,那么操作A在内存上所做的操作对操作B都是可见的,不管它们在不在一个线程。


在Java中,有以下天然的happens-before关系:

  • 程序顺序规则:一个线程中的每一个操作,happens-before于该线程中的任意后续操作。
  • 监视器锁规则:对一个锁的解锁,happens-before于随后对这个锁的加锁。
  • volatile变量规则:对一个volatile域的写,happens-before于任意后续对这个volatile域的读。
  • 传递性:如果A happens-before B,且B happens-before C,那么A happens-before C。
  • start规则:ThreadA start happens-before ThreadB start
  • join规则:如果线程A执行操作ThreadB.join()并成功返回,那么线程B中的任意操作happens-before于线程A从ThreadB.join()操作成功返回。


结束语

本节内容可能不像之前那么好理解,比较抽象,所以本文也有不足的地方,大家自己可以多查查一些资料,综合理解。下一节,带大家深入学习一下Java的volatile ~

相关文章
|
6月前
|
人工智能 前端开发
【ChatGPT 指令大全】怎么使用ChatGPT写履历和通过面试
【ChatGPT 指令大全】怎么使用ChatGPT写履历和通过面试
106 0
|
4月前
|
存储 安全 Java
Java面试题:深入探索Java内存模型,Java内存模型中的主内存与工作内存的概念,Java内存模型中的happens-before关系,volatile关键字在Java内存模型中的作用
Java面试题:深入探索Java内存模型,Java内存模型中的主内存与工作内存的概念,Java内存模型中的happens-before关系,volatile关键字在Java内存模型中的作用
37 1
|
1月前
经典面试题:用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题)
在 C 语言中,使用 `#define` 预处理指令可以为常量命名,提高代码可读性和易维护性。通过基本时间单位换算(1 年 = 365 天 × 24 小时 × 60 分钟 × 60 秒),可以计算出一年中的总秒数,并将其定义为 `SECONDS_IN_A_YEAR`。示例代码展示了如何定义和打印这一常量,最终输出一年中有 31536000 秒。
63 15
|
4月前
|
Java 数据库连接
Java面试题:Java内存模型中的happens-before关系,Java中的ThreadLocal是如何工作的?Java中的CountDownLatch和CyclicBarrier的区别?
Java面试题:Java内存模型中的happens-before关系,Java中的ThreadLocal是如何工作的?Java中的CountDownLatch和CyclicBarrier的区别?
37 0
|
4月前
|
Java
Java面试题:Java内存模型与并发编程知识点,解释Java中“happens-before”的关系,分析Java中的内存一致性效应(Memory Consistency Effects)及其重要性
Java面试题:Java内存模型与并发编程知识点,解释Java中“happens-before”的关系,分析Java中的内存一致性效应(Memory Consistency Effects)及其重要性
28 0
|
4月前
|
存储 安全 Java
Java面试题:Java内存模型中的主内存与工作内存是如何协同工作的?请解释Java内存模型中的可见性、原子性和有序性,举例说明Java内存模型中的happens-before关系
Java面试题:Java内存模型中的主内存与工作内存是如何协同工作的?请解释Java内存模型中的可见性、原子性和有序性,举例说明Java内存模型中的happens-before关系
36 0
|
4月前
|
Java 编译器
Java面试题:Java内存模型深度剖析,Java内存模型中的重排序(Reordering)现象,Java内存模型中的happens-before关系
Java面试题:Java内存模型深度剖析,Java内存模型中的重排序(Reordering)现象,Java内存模型中的happens-before关系
28 0
|
6月前
|
Linux
Linux面试常用命令大全(常用指令)
Linux面试常用命令大全(常用指令)
|
6月前
|
Java 编译器 程序员
【面试问题】什么是指令重排?
【1月更文挑战第27天】【面试问题】什么是指令重排?
|
6月前
|
Java 程序员
【面试问题】happens-before 是什么?
【1月更文挑战第27天】【面试问题】happens-before 是什么?