volatile 实现原理了解吗?

volatile 实现原理了解吗?

volatile 有两个作用,保证可见性有序性

volatile 怎么保证可见性的呢?

简单来说:读取和写入变量从原本的本地内存变成主内存中

相比 synchronized 的加锁方式来解决共享变量的内存可见性问题,volatile 就是更轻量的选择,它没有上下文切换的额外开销成本。

volatile 可以确保对某个变量的更新对其他线程马上可见,一个变量被声明为 volatile 时,线程在写入变量时不会把值缓存在寄存器或者其他地方,而是会把值刷新回主内存 当其它线程读取该共享变量 ,会从主内存重新获取最新值,而不是使用当前线程的本地内存中的值。

当对volatile变量进行写操作的时候,JVM会向处理器发送一条lock前缀的指令,将这个缓存中的变量回写到系统主存中。 所以,如果一个变量被volatile所修饰的话,在每次数据变化之后,值都会被强制写入主存。而其他处理器的缓存由于遵守缓存一致性协议,就会把变量的值从主存读取到自己的工作内存中。这就保证了volatile在并发编程中,其值在多个缓存中是可见的

例如,我们声明一个 volatile 变量 volatile int x = 0,线程 A 修改 x=1,修改完之后就会把新的值刷新回主内存,线程 B 读取 x 的时候,就会清空本地内存变量,然后再从主内存获取最新值。

volatile内存可见性

volatile 怎么保证有序性的呢?

简单来说:禁止指令重排,增加读写相关屏障

重排序可以分为编译器重排序和处理器重排序,valatile 保证有序性,就是通过分别限制这两种类型的重排序。

volatile重排序规则表

  • volatile读之后的任何操作不能重排序到volatile读之前(对应第二行)

    • 这么一个场景,需要根据volatile读出来的数据,进行后续的普通读写操作,若提前了,volatile数据是旧数据,导致语义错误。

    • volatile读之前的任何操作,就肯定不是基于该volatile变量的相关普通操作,所以不需要做相关屏障

  • volatile写之前的任何操作不能重排序到volatile写之后(对应第三列)

    • 这么一个场景,普通读写操作完成后才能更改volatile写操作,volatile写提前,说明还没完成操作你就改。

  • volatile写之后的volatile相关操作不能重排序到前面

    • 相当于对该volatile修饰的变量加锁

为了实现 volatile 的内存语义,编译器在生成字节码时,会在指令序列中插入内存屏障来禁止特定类型的处理器重排序。

  1. 在每个 volatile 写操作的前面插入一个StoreStore屏障

  2. 在每个 volatile 写操作的后面插入一个StoreLoad屏障

  3. 在每个 volatile 读操作的后面插入一个LoadLoad屏障

  4. 在每个 volatile 读操作的后面插入一个LoadStore屏障

  • 巧记:拆分成两个单词,读用Load,写用Store。LoadLoad读读,LoadStore读写·······

volatile写插入内存屏障后生成的指令序列示意图

volatile读插入内存屏障后生成的指令序列示意图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值