Volatile

15 篇文章 0 订阅
1 篇文章 0 订阅

volatile的作用

  • volatile的作用是保证共享变量的可见性,不能保证原子性,也不能保证线程安全。
  • volatile的作用是确保所有线程在同一时刻读取到的共享变量的值是一致的。
  • 如果某个线程对volatile修饰的共享变量进行修改,那么其他线程可以立刻看到这个更新。

硬件系统架构

在这里插入图片描述CPU首先使用自己的寄存器,然后使用速度更快的L1缓存,其中L1D缓存数据,L1I缓存指令。
L1缓存和次快的L2做同步数据;L2缓存和L3缓存做同步数据;L3缓存和主内存同步数据。

直写(write-through)

直写是透过本级缓存,直接把数据写到下级缓存(或直接到内存)中,如果对应数据被缓存了,我们同时更新缓存中的内容(甚至直接丢弃)。所以直写时缓存行永远和它对应的内存内容匹配。

回写(write-back)

缓存不会立刻把写操作传递到下一级,而是仅修改本级缓存中的数据,并且把对应的缓存数据标记为“脏“数据。脏数据会触发回写,也就是把对应的内容写到对应的内存或下一级缓存中。回写后,脏数据又变干净了。当一个脏数据被丢弃时,总是要先进行一次回写。

缓存一致性协议

解决缓存一致性方案有两种:

  1. 通过总线加LOCK#锁的方式;
  2. 通过缓存一致性协议。
    方案一存在一个问题,它是采用一种独占的方式来实现,即总线加LOCK#锁的话,只能有一个CPU能够运行,其他CPU都得阻塞,效率较为低下。
    【窥探技术+MESI协议】的出现,就是为了解决多核CPU时代缓存不一致的问题

窥探技术

  • ”窥探“背后的基本思想是,所有的数据传输都发生在一条共享的总线上,所有CPU都能看到这条总线。
  • 缓存本身是独立的,但是内存是共享资源,所有的内存访问都要经过仲裁(arbitrate):同一个指令周期中,只有一个缓存可以读写内存。
  • 窥探技术的思想是,缓存不仅仅在做内存传输的时候才和总线打交道,而是不停的窥探总线上发生的数据交换,跟踪其他缓存在做什么。
  • 所以当一个缓存代表它所属的CPU去读写内存时,其他CPU都会得到通知,它们以此来使自己的缓存保持同步。只要某个CPU一写内存,其他CPU马上就会知道这块内存在它们自己的缓存中对应的缓存行已经失效。

MESI协议

缓存系统操作的最小单位是缓存行,而MESI是缓存行四种状态的首写字母,任何多核系统中的缓存行都处于这四种状态之一。

  1. 失效(Invalid)缓存行:该CPU缓存中无该缓存行,或缓存中的缓存行已经失效;
  2. 共享(Shared)缓存行:缓存行的内容是同主内存内容保持一致的一份拷贝。在这种状态下的缓存行只能被读取不能被写入。多组缓存可以同时拥有针对同一内存地址的共享缓存行;
  3. 独占(Exclusive)缓存行:和S状态一样,也是和主内存内容保持一致的一份拷贝。区别在于,如果一个CPU持有了某个E状态的缓存行,那其他CPU就不能同时持该内容的缓存行,所以叫独占。这意味着,如果其他CPU原本也持有同一缓存行,那么它会马上变为失效状态。
  4. 已修改(Modified)缓存行:该缓存行已经被所属的CPU修改了。如果一个缓存行处于已修改状态,那么它在其他CPU缓存中的拷贝马上会变成失效状态。此外,已修改缓存行如果被丢弃或标记为失效,那么先要把它的内容回写到内存中。
    只有当缓存行处于E和M状态时,CPU才能去写它,也就是说只有这两种状态下,CPU时独占这个缓存行的;
    当CPU想写某个缓存时,如果它没有独占权,它必须先发一条我要独占权的请求给总线,这会通知其他CPU,把它们拥有的同一缓存行的拷贝失效;
    只有在获取独占权后,CPU才能开始修改数据。并且此时,这个CPU知道,这个缓存行只有一份拷贝,在我自己的缓存里,所以不会有任何冲突;
    反之,如果有其他CPU想读取这个缓存行,独占或已修改状态的缓存行必须先回到共享状态。

as-if-serial

数据依赖性

如果两个操作访问同一个变量,且这两个操作有一个为写操作,此时这两个操作就存在数据依赖性。数据依赖分下列三种类型:

名称代码示例说明
写后读a = 1;b = a;写一个变量后,再读这个变量
写后写a = 1;a = 2;写一个变量后,再写这个变量
读后写a = b;a = 1;都一个变量后,再写这个变量
**ps:这里所说的数据依赖性仅针对单个处理器中执行的指令序列和单个线程中执行的操作,不同处理器之间和不同线程之间的数据依赖性不被编译器和处理器考虑。**

as-if-serial

上面三种情况,只要重排两个操作的执行顺序,程序的执行结果将会被改变。
编译器和处理器可能会对操作做重排序。
编译器和处理器在重排序时,会遵守数据依赖性,
编译器和处理器不会改变存在数据依关系的两个操作的执行顺序。
as-if-serial语义的意思指:不管怎么重排序(编译器和处理器为了提高并行度),单线程程序的执行结果不能被改变。编译器运行时和处理器都必须遵守as-if-serial。
为了遵守as-if-serial语义,编译器和处理器不会对存在数据依赖关系的操作做重排序,因为这种重排序会改变执行结果。
但是,如果操作之间不存在数据依赖关系,这些操作可能被编译器和处理器重排序。
as-if-serial语义把单线程 程序保护了起来,遵守as-if-serial语义的编译器,runtime和处理器共同为编写单线程的程序员创建了一个幻觉:单线程程序是按程序的顺序来执行的。
as-if-serial语义使单线程程序员无需担心重排序会干扰他们,也无需担心内存可见性问题。

指令重排序

在执行程序时为了提高性能,编译器和处理器常常会对指令做重排序,重排序分为三种类型:

  1. 编译器优化的重排序
  2. 指令级并行的重排序
  3. 内存系统的重排序

volatile

volatile内存语义

volatile可以保证线程可见性且提供了一定的有序性,但是无法保证原子性。
在JVM底层volatile是采用“内存屏障”来实现的。
上述主要表明1.保证可见性,不保证原子性;2.禁止指令重排序。

可见性问题主要一个线程修改了共享变量值,而另一个线程却看不到。引起可见性问题的主要原因是每个线程拥有自己的工作内存。
volatile关键字能有效的解决这个问题。
java中的happen-before规则中对Happen-before的定义如下:

  • 程序顺序规则:一个线程中的每个操作,happen-before于该线程中的任意后续操作;
  • 监视器锁规则:对一个监视器的解锁,happen-before于随后对这个监视器的枷锁;
  • volatile变量规则:对一个volatile域的写,happen-before于任意后续对这个volatile域的读;
  • 传递性:如果A happen-before于 B,且B happen-before C,那么A happen-before C;
  • 线程的start()方法happen-before 该线程所有的后续操作;
  • 线程所有的操作happen-before其他线程在该线程上调用join返回成功后的操作。

volatile原理

为了实现volatile可见性和happen-before的语义。JVM底层是通过一个叫“内存屏障”的东西来完成。
内存屏障,也叫做内存栅栏,是一组处理器指令,用于实现对内存操作的顺序限制。
下面是完成上述要求的一些规则,在NO的地方就是需要用内存屏障来控制的。

是否可以重排序第二个操作
第一个操作普通读普通写volatile读volatile写
普通读NO
普通写NO
volatile读NONONONO
volatile写NONO
volatile的底层就是通过内存屏障来实现的。以下是上述规则所需要的内存屏障。
是否可以重排序第二个操作
第一个操作普通读普通写volatile读volatile写
普通读LoadStore
普通写StoreStore
volatile读LoadLoadLoadStoreLoadLoadLoadStore
volatile写StoreLoadStoreStore
屏障类型指令示例说明
LoadLoad
Barriers
Load1;
LoadLoad;
Load2;
确保Load1数据的装载,之前于Load2及所有后续装载指令的装载
StoreStore
Barriers
Store1;
StoreStore;
Store2;
确保Store1数据对其他处理器可见(刷新到内存),之前与Store2及所有后续存储指令的存储
LoadStore BarriersLoad; LoadStore; Store;确保Load数据装载,之前于Store及所有后续的存储指令刷新到内存
StoreLoad BarriersStore; StoreLoad; Load;确保Store数据对其他处理器变得可见(刷新到内存),之前于Load及所有后续装载指令的装载。StoreLoad Barriers会使该屏障之前的所有内存访问指令(存储和装载指令)完成之后,才执行该屏障之后的内存访问指令。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值