Volatile指令重排

it2026-01-10  7

Volatile禁止指令重排

计算机在执行程序时候,为了提高性能,编译器和处理器常常会对编译器进程优化,一般分为以下三种

​ 源代码->编辑器优化的重排–>指令并行的重排->内部系统工单重排–>最终执行指令

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

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

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

指令重排的例子
public class ResortSeqDemo { int a= 0; boolean flag = false; public void method01() { System.out.println("进去方法一"); a = 1; flag = true; } public void method02() { if(flag) { System.out.println("进去方法二"); 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之后,另外的一个线程立马调用方法method02,满足flag的判断,最终执行a+5,结果为5,这样同样会出现数据不一致的问题

出现这个问题的原因是,多线程情况下,线程交替执行,由于编辑器优化重排的存在,两个线程在使用变量能否保证一致性是无法确定的,结果无法预测。这样就需要通过volatile来休息,保证线程的安全性

Volatile针对指令重排做了什么

在字段voaltile针对指令重排做了什么,我们需要先了解一个概念,内存屏障,是一个CPU指令,它的作用有两个

保证特定的操作顺序保证某些变量内存可见性

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

内存屏障的作用

禁止指令重排刷新缓存,任何CPU上的线程都能读取到这些数据的最新版本也就是在volatile的写和读的时候,加入屏障,防止出现指令重排
线程安全获取保证

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

可以通过synchronise或者volatile关键字解决,他们都可以让一个线程改变的变量立即对其他线程可见

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

可以使用volatile关键字解决
说明参考

文章为看视频博客学习过程中总结,方便自己以后好复习

https://www.bilibili.com/video/BV18b411M7xz

http://moguit.cn/#/

最新回复(0)