深究可见性,原子性,有序性的解决方案之内存屏障
2022/3/20 7:35:34
本文主要是介绍深究可见性,原子性,有序性的解决方案之内存屏障,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
在了解内存屏障之前,我们先了解一下JMM模型的8种原子操作:
1.lock 锁定 : 把主内存中的一个变量标志为一个线程独享的状态
2.unlock 解锁 : 把主内存中的一个变量释放出来
3.read 读:将主内存中的变量读到工作内存中
4.load 加载:将工作内存中的变量加载到副本中
5.use 使用:当执行引擎需要使用到一个变量时,将工作内存中的变量的值传递给执行引擎
6.assign 赋值:将执行引擎收的的值赋值给工作内存中的变量
7.store 存储:将工作内存中的变量的值传到主内存中
8.write 写入:将store得到值放到主内存的变量中
并且JMM内存模型还规定了以上操作必须遵守的规则:
1.如果要把一个变量从主内存中复制到工作内存,就需要按顺寻地执行read和load操作, 如果把变量从工作内存中同步回主内存中,就要按顺序地执行store和write操作。但Java内存模型只要求上述操作必须按顺序执行,而没有保证必须是连续执行。
2.不允许read和load、store和write操作之一单独出现
3.不允许一个线程丢弃它的最近assign的操作,即变量在工作内存中改变了之后必须同步到主内存中。
4.不允许一个线程无原因地(没有发生过任何assign操作)把数据从工作内存同步回主内存中。
5.一个新的变量只能在主内存中诞生,不允许在工作内存中直接使用一个未被初始化(load或assign)的变量。即就是对一个变量实施use和store操作之前,必须先执行过了assign和load操作。
6.一个变量在同一时刻只允许一条线程对其进行lock操作,但lock操作可以被同一条线程重复执行多次,多次执行lock后,只有执行相同次数的unlock操作,变量才会被解锁。lock和unlock必须成对出现
7.如果对一个变量执行lock操作,将会清空工作内存中此变量的值,在执行引擎使用这个变量前需要重新执行load或assign操作初始化变量的值
8.如果一个变量事先没有被lock操作锁定,则不允许对它执行unlock操作;也不允许去unlock一个被其他线程锁定的变量。
9.对一个变量执行unlock操作之前,必须先把此变量同步到主内存中(执行store和write操作)
对于内存屏障而言,关注的就是store和load操作。
根据JMM模型规定,read和load,store和write必须同时出现,并且按照顺序执行,所以执行完load操作,必然是加载了主内存的值的,但不能保证这两操作时是原子性的,同样的道理,执行store也是一样的,都无法保证操作的原子性,那么内存屏障又是如何解决这个问题的呢?
首先看硬件层面的内存屏障:
1. lfence,是一种Load Barrier 读屏障。在读指令前插入读屏障,可以让高速缓存中的数据失效,重新从主内存加载数据,其实就是告诉操作系统,后面的值给我去主存中取。
2. sfence, 是一种Store Barrier 写屏障。在写指令之后插入写屏障,能让写入缓存的最新数据写回到主内存,其实就是把我写的这条数据直接刷到主存,看着和上面那条差不多都是刷最新的数据,但区别在于其他核心不一定会来取
3. mfence, 是一种全能型的屏障,具备ifence和sfence的能力,就是把当前缓存行的数据修改过的最新值刷入主存,其他的失效,重新从主存获取。
4. lock前缀也能实现类似的效果,它通过对总线/缓存行加锁,执行后面的指令,这个时候所有访问这条总线/缓存行的请求都会被阻塞,直到锁释放。lock指令可以保证前面的修改都会刷新到主存,并且释放锁后会使所有所有对应缓存行失效,这样就可以达到和内存屏障一样的效果
java中unsafe包也提供了类似的屏障:
public native void loadFence(); // 读屏障 public native void storeFence(); // 写屏障 public native void fullFence(); //两者都有底层实现也都是差不多的,其实内存屏障的另外一个含义就是可以禁止重排序,屏障就是一道栅栏,前面的指令必须在前面执行完,后面的不能跳到前面执行,禁止代码过度优化。 最后我们再看下上面的问题,如何保证store load 和read write之间的原子性,最简单的就是加锁,但是这样的消耗太大,而内存屏障通过一道栅栏的形式,并保证缓存一致性,同样也实现了写与读之间的原子性。
这篇关于深究可见性,原子性,有序性的解决方案之内存屏障的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-26消息中间件源码剖析教程
- 2024-11-26JAVA语音识别项目资料的收集与应用
- 2024-11-26Java语音识别项目资料:入门级教程与实战指南
- 2024-11-26SpringAI:Java 开发的智能新利器
- 2024-11-26Java云原生资料:新手入门教程与实战指南
- 2024-11-26JAVA云原生资料入门教程
- 2024-11-26Mybatis官方生成器资料详解与应用教程
- 2024-11-26Mybatis一级缓存资料详解与实战教程
- 2024-11-26Mybatis一级缓存资料详解:新手快速入门
- 2024-11-26SpringBoot3+JDK17搭建后端资料详尽教程