volatile 禁止指令重排序

news2024/9/27 5:50:47

计算机在执行程序时,为了提高性能,编译器和处理器常常会对指令重排,一般分为以下三种:

源代码 -> 编译器优化的重排 -> 指令并行的重排 -> 内存系统的重排 -> 最终执行指令

单线程环境里面确保最终执行结果和代码顺序的结果一致

处理器在进行重排序时,必须要考虑指令之间的数据依赖性

多线程环境中线程交替执行,由于编译器优化重排的存在,两个线程中使用的变量能否保证一致性是无法确定的,结果无法预测。

指令重排 - example 1

public void mySort() {
	int x = 11;
	int y = 12;
	x = x + 5;
	y = x * x;
}

按照正常单线程环境,执行顺序是 1 2 3 4

但是在多线程环境下,可能出现以下的顺序:

  • 2 1 3 4
  • 1 3 2 4

上述的过程就可以当做是指令的重排,即内部执行顺序,和我们的代码顺序不一样

但是指令重排也是有限制的,即不会出现下面的顺序

  • 4 3 2 1

因为处理器在进行重排时候,必须考虑到指令之间的数据依赖性

因为步骤 4:需要依赖于 y的申明,以及x的申明,故因为存在数据依赖,无法首先执行

例子

int a,b,x,y = 0

线程1线程2
x = a;y = b;
b = 1;a = 2;
x = 0; y = 0

因为上面的代码,不存在数据的依赖性,因此编译器可能对数据进行重排

线程1线程2
b = 1;a = 2;
x = a;y = b;
x = 2; y = 1

这样造成的结果,和最开始的就不一致了,这就是导致重排后,结果和最开始的不一样,因此为了防止这种结果出现,volatile就规定禁止指令重排,为了保证数据的一致性

指令重排 - example 2

比如下面这段代码

/**
 * ResortSeqDemo
 *
 * @create: 2020-03-10-16:08
 */
public class ResortSeqDemo {
    int a= 0;
    boolean flag = false;

    public void method01() {
        a = 1;
        flag = true;
    }

    public void method02() {
        if(flag) {
            a = a + 5;
            System.out.println("reValue:" + a);
        }
    }
}

我们按照正常的顺序,分别调用method01() 和 method02() 那么,最终输出就是 a = 6

但是如果在多线程环境下,因为方法1 和 方法2,他们之间不能存在数据依赖的问题,因此原先的顺序可能是

a = 1;
flag = true;

a = a + 5;
System.out.println("reValue:" + a);
        

但是在经过编译器,指令,或者内存的重排后,可能会出现这样的情况

flag = true;

a = a + 5;
System.out.println("reValue:" + a);

a = 1;

也就是先执行 flag = true后,另外一个线程马上调用方法2,满足 flag的判断,最终让a + 5,结果为5,这样同样出现了数据不一致的问题

为什么会出现这个结果:多线程环境中线程交替执行,由于编译器优化重排的存在,两个线程中使用的变量能否保证一致性是无法确定的,结果无法预测。

这样就需要通过volatile来修饰,来保证线程安全性

Volatile针对指令重排做了啥

Volatile实现禁止指令重排优化,从而避免了多线程环境下程序出现乱序执行的现象

首先了解一个概念,内存屏障(Memory Barrier)又称内存栅栏,是一个CPU指令,它的作用有两个:

  • 保证特定操作的顺序
  • 保证某些变量的内存可见性(利用该特性实现volatile的内存可见性)

由于编译器和处理器都能执行指令重排的优化,如果在指令间插入一条Memory Barrier则会告诉编译器和CPU,不管什么指令都不能和这条Memory Barrier指令重排序,也就是说 通过插入内存屏障禁止在内存屏障前后的指令执行重排序优化。 内存屏障另外一个作用是刷新出各种CPU的缓存数,因此任何CPU上的线程都能读取到这些数据的最新版本。

 也就是过在Volatile的写 和 读的时候,加入屏障,防止出现指令重排的

线程安全获得保证

工作内存与主内存同步延迟现象导致的可见性问题

  • 可通过synchronized或volatile关键字解决,他们都可以使一个线程修改后的变量立即对其它线程可见

对于指令重排导致的可见性问题和有序性问题

  • 可以使用volatile关键字解决,因为volatile关键字的另一个作用就是禁止重排序优化

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/129757.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AWS人工智能主题学习月:深度学习入门笔记

目录 一、深度学习入门课程的学习重点📕 二、简单介绍一下深度学习和神经网络💡 1.深度学习 2.神经网络 3.深度学习储备知识拓展 三、深度学习生产生活实际案例🚗 四、深度学习的框架介绍🌳 总结 深度学习是机器学习中的一…

Arch/Manjaro安装搜狗输入法

装好系统以后,没有输入法,只能打英文的感觉很难受,现在我们来看看如何给Arch系列的系统安装搜狗输入法。 加入Skype Linux群来这里一起解决问题吧!腾讯不支持Linux,让我们一起抛弃微信~ Join conversationhttps://join…

⌈ 2022杀青 ⌋ 一个普通人的年终总结,这一年我获得了更多的新鲜体验 | 普通而平凡的一年 | 向前走,走到光里 | 2023你好

💛年度总结💛 时间转瞬便是年末,在此写下告别 成长是一场踏实的幻灭 有哭有笑有酸有甜,失去与获得也同在 即使生活再忙,也不要忘记那些美好治愈我们的瞬间 起起伏伏的日子,这依然是很长很好的一年&…

python 爬虫 使用selenium 控制浏览器 进行搜索操作

首先需要安装selenium: 第一种:可以自己下载selenium tar.gz包,下载到python目录下:解压到当前文件夹 在cmd命令行:进入到解压包中,进行安装。安装完成之后,如果是eclipse中,请 clean project之…

APSIM练习3:氮循环

在本练习中,您将观察休耕情况下的氮肥循环;尿素转化为铵,铵转化为硝酸盐,以及土壤硝酸盐通过反硝化作用流失。此模拟将介绍编辑一个简单的管理器规则以及绘制模拟结果的更多高级功能。 开始基于 Continuous Wheat.apsim 的新模拟。…

【20221230】栈和队列的小结

一、栈(stack) 栈是先进后出的(FILO)的数据结构,它只有一个出口。 二、队列 队列是一种先进先出(FIFO)的数据结构,它有两个出口。 栈和队列是STL(C标准库)里面…

【攻防世界】Web easyupload

知识点讲解 本题的主要考点为利用fastcgi的.user.ini特性进行任意命令执行 关于.user.ini文件是怎么利用的,可以点此查看非常详细,我这里截取一段 .user.ini实际上就是一个可以由用户“自定义”的php.ini,我们能够自定义的设置是模式为“PHP…

创作者身份认证申请规则及审核标准

当前创作者身份主要包括优质创作者、新星创作者、其他(特殊情况)。 有一些身份认证,比如:企业员工认证、学生认证等,不属于创作者身份认证范畴,申请的时候需要找到对应的认证进行申请(https://…

python【多态特性】

多态:同样的行为(函数),传入不同的对象,得到不同的状态 特点:通过继承的方式体验抽象动作相同而具体实现细节不同细节的特性 如,定义函数(方法),通过类型注…

NetInside帮助IT提高应用性能分析能力(一)

前言 某大学信息中心老师反应,用户反馈科研创新服务器平台有访问慢的情况,需要通过流量分析系统来了解系统的运行情况,此报告专门针对系统的性能数据做了分析。 信息中心已部署NetInside流量分析系统,使用流量分析系统提供实时和…

进销存管理系统哪个比较好?

在如今互联网的刺激之下,企业之间的竞争逐渐加剧,很多企业之所以会逐渐被市场淘汰,主要原因都来源于管理上的混乱,而进销存软件的出现可以帮助企业解决管理难题。 选择一款合适的省心的进销存软件,有效提升企业的核心…

Redis中缓存穿透、击穿、雪崩以及解决方案

缓存穿透 理解: 缓存穿透是指查询一个根本不存在的数据,缓存层和持久层都不会命中。在日常工作中出于容错的考虑,如果从持久层查不到数据则不写入缓存层,缓存穿透将导致不存在的数据每次请求都要到持久层去查询,失去…

【正点原子FPGA连载】第八章使用Vitis开发Linux应用摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

1)实验平台:正点原子MPSoC开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id692450874670 3)全套实验源码手册视频下载地址: http://www.openedv.com/thread-340252-1-1.html 第八章使用Vitis…

日本知名汽车零部件公司巡礼系列之株式会社140

株式会社140 业务内容: ・特殊切削工具汽车零件加工用特殊工具的设计、制作・特殊零件海斯、超硬、陶瓷、cBNCD工具的设计与制作・制造用夹具、安装用具、检查用具、定位用具、消耗工具等一制造装饰零件相关的装置或专用机的构成零件等・模具零件制作…钳子、模具…

Spring Boot整合MyBatis(保姆级教程)

前言 MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objec…

【正点原子FPGA连载】第九章Linux图形界面的搭建摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

1)实验平台:正点原子MPSoC开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id692450874670 3)全套实验源码手册视频下载地址: http://www.openedv.com/thread-340252-1-1.html 第九章Linux图形…

单片机之震动传感器、继电器、433M无线发射接收等模块介绍及应用

目录 一、震动传感器模块 二、继电器介绍 三、433M无线发射接收模块 1、 无线控制报警器代码 2、电动车简易防盗器代码实现 一、震动传感器模块 单片机供电VCC GND接单片机 产品不震动,输出高电平、模块上的AO口 产品震动,输出低电平&#xff0c…

Python使用库(一)

Python使用库 库 就是是别人已经写好了的代码, 可以让我们直接拿来用. 荀子曰: “君子性非异也,善假于物也” 一个编程语言能不能流行起来, 一方面取决于语法是否简单方便容易学习, 一方面取决于生态是否完备. 所谓的 “生态” 指的就是语言是否有足够丰富的库, 来…

day11-分类和static

1.案例驱动模式 1.1案例驱动模式概述 (理解) 通过我们已掌握的知识点,先实现一个案例,然后找出这个案例中,存在的一些问题,在通过新知识点解决问题 1.2案例驱动模式的好处 (理解) 解决重复代码过多的冗余,提高代码的复用性解决业务逻辑聚集紧密导致的可读性差,提高代码的可…

【python Turtle源码】教你如何画一只迎福虎将~

前言 大家早好、午好、晚好吖 ❤ ~ 代码展示 导入模块 from turtle import * import time因代码体量有点多 这里就给大家部分展示了,有需要的可以文章下方名片获取哦~ (或者评论已点赞收藏,求代码,我私你呀) COLO…