6.什么是内存屏障?具有什么作用?

简介: 6.什么是内存屏障?具有什么作用?

什么是内存屏障?

小陈:老王,上一篇你引出了volatile底层是通过内存屏障来解决可见性和有序性问题的。首先我想问一下什么是内存屏障?

老王:内存屏障啊,本质上也是一种指令,只不过它具有屏障的作用而已。

小陈:额,这怎么说...


老王:首先内存屏障是一种指令,无论是在JAVA内存模型还是CPU层次,都是有具体的指令对应的,是一种特殊的指令。

小陈:嗯嗯,它是一种特殊的指令。还是不明白......

小陈:然后呢?

老王:然后这种指令具有屏障的作用所谓屏障,也就是类似关卡,类似栅栏,具有隔离的作用。

小陈:那它是怎么实现隔离作用的,能否搞个例子讲一下。

老王:哈哈,这个举例没问题,我先跟你说说内存屏障的分类,后面再给你实例讲一下:

老王:按照内存屏障的分类,我理解有两类。

(1)一类是强制读取主内存强制刷新主内存的内存屏障,叫做Load屏障Store屏障

(2)另外一类是禁止指令重排序内存屏障,有四个分别叫做LoadLoad屏障StoreStore屏障LoadStore屏障StoreLoad屏障

老王:下面再给你介绍一下这两类内存屏障各自的作用:

强制读取/刷新主内存的屏障

Load屏障:执行读取数据的时候,强制每次都从主内存读取最新的值。

Store屏障:每次执行修改数据的时候,强制刷新回主内存

先给你画图讲解一下Load屏障

image.png

如上图所示:在工作内存的变量名、变量的值之前有一道关卡或者栅栏,导致变量 i 获取不到工作内存中的值,所以每次只好主内存重新加载咯

然后再给讲一下Store屏障

image.png

如上图所示,每次执行assign指令将数据变更之后,后面都会紧紧跟着一个Store屏障,让你立刻刷新到主内存。

老王:小陈,我画这两图讲强制读取和刷新主内存的屏障(Load屏障Store屏障),你看懂了嘛?

小陈:也就是说,只要加了Load屏障相当于加了一个栅栏,不管工作内存是否有数据,都是从主内存读取数据。只要加了Store屏障具有强制作用,进行assign操作将变量更改了之后,立刻将变量刷新到主内存里面是吗?

老王:是的,就是这么一个道理,上面的图只是为了方便你理解画出来的,实现上并不一定完全跟图的一样,但是原理差不多。

小陈:嘿嘿,老王真棒......

禁止指令重排序的屏障

老王:好了,下面再给你讲讲另外一类的内存屏障,下面这类的内存屏障的作用是禁止指令重排序,JAVA内存模型层次关于禁止重排序有下面4种屏障:

LoadLoad屏障

序列:load1指令 LoadLoad屏障 load2指令

作用:在load1指令和load2指令之间加上 LoadLoad屏障,强制先执行load1指令再执行load2指令;load1指令和load2指令不能进行重排序(LoadLoad屏障  前面load指令禁止和屏障后面的load指令进行重排序)。

StoreStore屏障

序列:store1指令 StoreStore屏障 store2指令

作用:在store1指令和store2指令之间加上StoreStore屏障,强制先执行store1指令再执行store2指令;store1指令不能和store2指令进行重排序(StoreStore屏障  前面的store指令禁止和屏障后面的store指令进行重排序

LoadStore屏障

序列:load1指令 LoadStore屏障 store2指令

作用:在load1指令和store2指令之前加上LoadStore屏障,强制先执行load1指令再执行store2指令;load1指令和store2执行不能重排序(LoadStore屏障  前面的load执行禁止和屏障后面的store指令进行重排序

StoreLoad屏障

序列:store1指令 StoreLoad屏障 load2指令

作用:在store1指令和load2指令之间加上StoreLoad屏障,强制先执行store1指令再执行load2指令;

store1指令和load2指令执行不能重排序(StoreLoad屏障  前面的Store指令禁止和屏障后面的Store/Load指令进行重排

老王:小陈,我上面说的这几种内存屏障,你能理解吗?

小陈:感觉听着有点玄乎啊,实际上是怎么禁止重排序的啊...

老王:我下面给你画个图,以StoreStore屏障和StoreLoad屏障举个例子,你就知道大概是什么意思了:

image.png

(1)有三个区域分别是区域1区域2区域3

(2)区域1和区域2加了 StoreStore屏障,这样区域1和区域2的Store指令被隔离开来,不能重排了

(3)区域2和区域3加了StoreLoad屏障,这样区域2和区域3的Store指令、Load指令被隔离开来,不能重排了

(4)就相当于搞了个栅栏,禁止各个区域之间的指令跳来跳去的,否则就会导致乱序执行

小陈:哎呀,原来是搞了个栅栏啊,说白了就是相当于搞了个围墙,不让各个指令之间跳来跳去的,这样达到禁止区域之间重排序的效果。

小陈:牛啊,老王;看起来这么深奥的道理,竟被你搞个图这么简单的说清楚了,献上我的膝盖...


老王:嘿嘿,还好还好......

小陈:内存屏障的底层是怎么保证可见性和有序性的,通过这次讨论我明白了但是volatile是怎么使用内存屏障的我还不明白啊?

老王:别急啊,小陈。慢慢来,今天我们先讲到内存屏障这里,volatile怎么使用内存屏障的?我们下一章再说一下。

其实不只是volatile使用到了内存屏障,还有像是synchronized关键字底层也是用到内存屏障的。

今天我们先说到这里,下一篇《volatile怎么通过内存屏障保证可见性和有序性? 》我们来继续讨论

小陈:好的,老王,我们下一章见。

相关文章
|
存储 缓存 Java
【并发编程的艺术】详解指令重排序与数据依赖
本章详细描述了指令重排序的场景,条件,以及数据依赖、控制依赖对指令重排序的影响。总结如下: 单线程程序,对存在控制依赖的操作执行重排序,不会改变执行结果;但在多线程程序中,对存在控制依赖的操作执行重排序,可能会改变程序的执行结果!这就是多线程执行时出现并发问题的根本原因,切记。
144 0
|
缓存
指令重排序的探讨
指令重排序是现代处理器为了提高指令级并行性和性能而进行的一种优化技术。在高并发场景下,指令重排序可能会引发一些问题,本文将详细介绍指令重排序的概念、原因、影响以及如何解决这些问题。
184 0
|
5月前
|
存储 安全 开发者
JMM的组成和它的作用
JMM的组成和它的作用
47 0
|
6月前
|
缓存 Java 编译器
关于volatile与指令重排序的探讨
关于volatile与指令重排序的探讨
80 1
|
6月前
|
Java 编译器 开发者
为什么代码会重排序
在并发编程中,重排序是一项为了提高性能而进行的优化策略。理解重排序的原理和可能引发的问题对于编写高效且正确的多线程代码至关重要。Java提供了一些机制,如内存屏障,来帮助开发者在多线程环境下保持程序的正确性和可靠性。
64 0
|
存储 缓存 Java
volatile的扩展分析(2)——happens-before 与 内存屏障
volatile的扩展分析(2)——happens-before 与 内存屏障
315 0
volatile的扩展分析(2)——happens-before 与 内存屏障
|
安全 Java
架构系列——面试必问:volatile的可见性、防止指令重排序以及不能保证原子性的解决方式
架构系列——面试必问:volatile的可见性、防止指令重排序以及不能保证原子性的解决方式
|
缓存 安全 Java
volatile底层的实现原理:volatile关键字的作用、内存模型、JMM规范和CPU指令
volatile底层的实现原理:volatile关键字的作用、内存模型、JMM规范和CPU指令
162 0
|
存储 缓存 安全
基础篇:深入JMM内存模型解析volatile、synchronized的内存语义
总线锁定:当某个CPU处理数据时,通过锁定系统总线或者是内存总线,让其他CPU不具备访问内存的访问权限,从而保证了缓存的一致性
97 0
|
编译器
什么是指令重排序?
什么是指令重排序?
什么是指令重排序?