计算机在执行程序时候,为了提高性能,编译器和处理器常常会对编译器进程优化,一般分为以下三种
源代码->编辑器优化的重排–>指令并行的重排->内部系统工单重排–>最终执行指令
单线程环境里面确保最终执行结果和代码顺序的结构一致
处理器在进行重排时候,必须要考虑指令之间的数据依赖性
多线程环境中线程交替执行,由于编译器优化重排的存在,两个线程使用的变量能否安保证一致性无法确定,结果无法预测
我们安装正常的顺序,分别调用方法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来休息,保证线程的安全性
在字段voaltile针对指令重排做了什么,我们需要先了解一个概念,内存屏障,是一个CPU指令,它的作用有两个
保证特定的操作顺序保证某些变量内存可见性由于编译器和处理器都能执行指令重排的优化,如果在指令间插入一条Memory Barrier则会告诉编译器和CPU,不管什么指令都不能和这条Memory Barrier指令重排序,也就是说,通过插入内存屏障禁止在内存屏障前后的指令执行重排序优化。内存屏障的另外一个作用是刷新各种CPU缓存数,因此任何CPU上的线程都能读取到这些数据的最新版本
内存屏障的作用
禁止指令重排刷新缓存,任何CPU上的线程都能读取到这些数据的最新版本也就是在volatile的写和读的时候,加入屏障,防止出现指令重排工作内存和主内存同步延迟现象导致可见性问题
可以通过synchronise或者volatile关键字解决,他们都可以让一个线程改变的变量立即对其他线程可见对于指令重排导致的可见性问题和有序性问题
可以使用volatile关键字解决文章为看视频博客学习过程中总结,方便自己以后好复习
https://www.bilibili.com/video/BV18b411M7xz
http://moguit.cn/#/
