jvm指令重排

article/2025/4/30 22:37:28

JVM会在不影响正确性的前提下调整语句(指令)的顺序。

例如下代码:

static int i;
static int j;
// 在某个线程内执行如下赋值操作
i = ...; 
j = ...; 
//可以看到,至于是先执行 i 还是 先执行 j ,对最终的结果不会产生影响。所以,上面代码真正执行时,既可以是
i = ...; 
j = ...; 
//也可以是
j = ...;    
i = ...; 

这种特性被称为指令重排,多线程的某些情况下指令重排会影响正确性。

1、为什么会有指令重排这项优化呢?

一个cpu执行指令是逐条执行的,但是如果我们把指令在进行划分,比如划分为:取指令 - 指令译码 - 执行指令 - 内存访问 - 数据 写回 五个阶段,那么Cpu实际执行过程是这样的

image-20220507092816313

每个CPU中有不同的执行单元(位移单元、运算单元等),对应指令执行的不同步骤,在并行指令集引入之前,一个CPU只能同时执行一条指令,所以CPU中各个单元同一时间只有一个单元在工作。

并行指令集引入之后,同一时间CPU的各个单元可以同时运行,实现了真正意义上的指令级的并行操作。这意味着CPU同一时刻能够执行多条指令。

虽然CPU能够并行执行指令了,但是,有一些指令需要依赖前面指令的执行结果,所以不能并行执行,这时候就可以通过指令重排优化来实现CPU并行指令的目的,例如:

image-20220507095836711

重新排序以后就af就可以并行执行。

2、CPU如何实现指令并行执行。

在研究指令重排是如何影响并发正确性之前,先额外看一下cpu如何实现指令并发执行

答案是流水线作业!

现代 CPU 支持多级指令流水线,例如支持同时执行 取指令 - 指令译码 - 执行指令 - 内存访问 - 数据写回 的处理 器,就可以称之为五级指令流水线。这时 CPU 可以在一个时钟周期内,同时运行五条指令的不同阶段(相当于一 条执行时间最长的复杂指令),IPC = 1(IPC是每个时钟周期能运行的指令数),本质上,流水线技术并不能缩短单条指令的执行时间,但它变相地提高了 指令地吞吐率。

image-20220507100810720

3、指令重排是如何影响并发正确性的

如下代码可能的执行结果 有:4,1和0

int num = 0;
boolean ready = false;
// 线程1 执行此方法
public void actor1(I_Result r) {if(ready) {r.r1 = num + num;} else {r.r1 = 1;}
}
// 线程2 执行此方法
public void actor2(I_Result r) { num = 2;ready = true; 
}

4和1恒容易理解,0就 有一些不可思议。而结果0出现的原因就是对actor2方法中的两行代码进行了重排序,交换了他们的执行次序。

但是在单线程的情形下,两个方法顺次执行,永远不会出现0这个结果。

4、如何解决多线程下的指令重排带来的问题

使用volatile的内存屏障功能。

使用volatile修饰的变量,在读或写之后会形成内存读写屏障的效果。

(1)写屏障

对volatile修饰的变量进行写操作之后(该操作被称为写屏障),该变量之前的代码执行结果会被写入到主存。同时会保证,写屏障之前的代码不会被重排序到写屏障之后。

(2)读屏障

对volatile修饰的变量进行读操作之后(该操作被称为读屏障),该变量之后的代码读取共享变量时会直接从主存中读取。同时,保证读屏障之后的代码不会被重排序到读屏障之前。

通过读写屏障也就解释了为什么volatile能够保证可见性和有序性:

  • 可见性 :无论在哪个线程金星了修改都会立刻同步主存,同时从主存读。

    • 写屏障(sfence)保证在该屏障之前的,对共享变量的改动,都同步到主存当中
    • 而读屏障(lfence)保证在该屏障之后,对共享变量的读取,加载的是主存中最新数据
  • 有序性

    • 写屏障会确保指令重排序时,不会将写屏障之前的代码排在写屏障之后
    • 读屏障会确保指令重排序时,不会将读屏障之后的代码排在读屏障之前

所以解决上述问题只需要在ready变量前用volatile修饰即可:这样就保证ready=true(写屏障)之前的代码(num=2)不会被重排序ready=true(写屏障)之后。

int num = 0;
volatile boolean ready = false;
// 线程1 执行此方法
public void actor1(I_Result r) {if(ready) {r.r1 = num + num;} else {r.r1 = 1;}
}
// 线程2 执行此方法
public void actor2(I_Result r) { num = 2;ready = true; 
}

image-20220507110854143

注意:

  • 同步代码块越短越好

  • synchronized能解决有序、可见、原子性问题,但是不能防止重排序现象的发生。对于重排序这一点,如果共享变量的所有操作均在synchronized代码块内,是不会出现重排序导致的程序结果错误。


http://chatgpt.dhexx.cn/article/CaIwn1jv.shtml

相关文章

CSS重排与重绘总结

昨天面试被问到了什么是重排和重绘,回答的并不是很好,下面来总结一下:关于CSS重排和重绘的概念,在制作中考虑浏览器的性能,减少重排能够节省浏览器对其子元素及父类元素的重新渲染;避免过分的重绘也能节省浏…

Leetcode之重排链表

文章目录 前言一、线性表二、寻找链表中点 链表逆序 合并链表总结 前言 题目如下: 重排链表(点我) 一、线性表 因为链表不能下标访问元素,所以我们不能随机访问链表中的元素,因此我们采用数组来存储链表中的每一个元素。利用…

推荐算法架构4:重排

系列文章,请多关注 推荐算法架构1:召回 推荐算法架构2:粗排 推荐算法架构3:精排 推荐算法架构4:重排 1 总体架构 重排主要解决三大问题:用户体验

Cadence Orcad元器件位号重排与原理图页序号重排

一.为什么需要元器件位号重排 在画原理图的过程中,增删改的操作是很多的,这使得元器件位号是通常是混乱的。在绘制完成后,通常需要重排一下位号,这样同一功能块的元器件位号是相邻的,这使得画PCB时能比较方便的确定某一…

你真的了解重排和重绘吗?

做过前端开发的小伙伴就算不是非常理解重排与重绘,但是肯定都听过这两个词。那为什么这两个东西这么重要?因为他与我们的页面性能息息相关,今天,我们就来好好研究一下这两个东西。 浏览器的渲染流程 在讲解重排和重绘之前&#…

简单易懂之什么是重排和重绘?

文章目录 目录 一、浏览器页面是怎么生成的? 二、什么是重排和重绘? 1.什么时候发生重绘? 2.如何优化重排效率? 一、浏览器页面是怎么生成的? 首先让我们来先了解一下浏览器页面生成的过程 文字解析: 1&am…

重排(回流)和重绘

什么是重排和重绘 浏览器下载完页面所有的资源后,就要开始构建DOM树,与此同时还会构建渲染树(Render Tree)。(其实在构建渲染树之前,和DOM树同期会构建Style Tree。DOM树与Style Tree合并为渲染树) 浏览器下载完成所有…

什么是重排和重绘

简答 1.重排(重新排列)> 指元素的位置发生改变的时候浏览器会进行重排 2.重绘(重新绘制)>指元素的基本样式发生改变是发生重绘,比如颜色等。。。 细答 前提概要(浏览器使用两个引擎进行工作一是渲…

Docker之发布自己的镜像

首先应当是先登入 其次是将镜像重新打包 在此处使用命令 docker commit fb6af4e48c14 zlx/centos7_vim:1.0 将一个容器生成一个新的镜像 然后把这个镜像改成dockerhub的仓库名,push一下就行了,dockerhub毕竟是国外的网站,换成阿里云就好了

Matlab调用excel数据绘制折线图

如题,matlab之前没接触过,但是电脑上一直有安装,有些老师需要做几张图放论文里,所以尝试了一下(excel其实效果也行,但matlab感觉更专业) x2:2:778;%x轴上的数据,第一个值代表数据开…

COGS 2075. [ZLXOI2015][异次元圣战III]ZLX的陨落

★★☆ 输入文件:ThefallingofZLX.in 输出文件:ThefallingofZLX.out 简单对比时间限制:1 s 内存限制:256 MB 【题目描述】 正当革命如火如荼,情侣教会日薄西山之时,SOX和FFF的分歧却越来越大&#…

Codechef GRAPHCNT 支配树学习及tarjan算法求解

[Codechef GRAPHCNT]新年的有向图 【题目描述】 zlx同学在学习数论时,被虐了一脸,丧心病狂的他决定去报复社会。 zlx在公园里埋下N颗地雷,用来炸飞在春节期间秀恩爱的情侣。这N颗地雷由M条有向边连接成为一个有向图,zlx则在1号地雷处引爆1号地雷可以到达的地雷。现在,为了…

大数据体系建设经验分享

分享嘉宾:吴荣彬 分贝通 大数据部负责人 编辑整理:zlx 出品平台:DataFunTalk 导读:本文将介绍分贝通在大数据领域的一些建设经验。分贝通在ToB领域是一个年轻的公司,成立六年多,大数据体系刚刚建立一年多&a…

将二维数组转为稀疏数组进行压缩,提高效率

** 稀疏数组 ** ##基本介绍: 当一个数组中大部分元素为0,或者为同一个值的数组时,可以使用稀疏数组来保存该数组。 稀疏数组的处理方法是: 1) 记录数组一共有几行几列,有多少个不同的值 2) 把具有不同值的元素的行列…

A数字三角 怨种

问题描述 有一天,无聊的 zlx 从 1 开始数数,同时在纸上写下每个数的个位数字。因为她非常热爱直角三角形,所以在纸上写下的数字按照直角三角形排列。现在告 诉你写她了 N 行数字,要求你打出这些数字。 输入格式 一行一个数 N&a…

聊聊Spring的IOC,AOP、DI、MVC

1 聊聊Ioc,Di,Mvc,Aop 不想看下面内容的,直接上代码连接,以下代码都有注释 传送门 1.1 看启动项 我们先来看看启动项 package com.tian;import com.tian.springframework.annotation.SpringBootApplication; import com.tian.springframework.config…

ZYNQ DDS产生载波FFT变换

环境:vivado2017.4,快速傅里叶变换V9.0 IP核 一,介绍:Xilinx FFT IP核是一种计算DFT的有效方式。 特点:前向变换(FFT)和反向变换(IFFT)在复数空间,并且可…

并发队列中迭代器弱一致性原理探究

一、前言 并发队列里面的Iterators是弱一致性的,next返回的是队列某一个时间点或者创建迭代器时候的状态的反映。当创建迭代器后,其他线程删除了该元素时候并不会抛出java.util.ConcurrentModificationException异常,能够保持创建迭代器后的元…

浅谈同构类问题的骗分算法

ZLX算法-----同构类问题的有力骗分算法前言:ZLX算法是一种解决判定性同构问题的蒙特卡罗式骗分算法:总能在确定的运行时间内出解,但是得到的解不能保证正确。尽管由于具有拓扑序,树同构和仙人掌同构存在多项式算法,但是…

win10下修改C盘用户文件夹名

之前安装一个程序出错,上网百度后是用户文件夹名为中文,也在网上找了好多方法,有同步的,有修改注册表的,最后我找到一个比较简单而且数据保留完整的方法。这种方法也会自动修改用户的环境变量,不过修改完后…