volatile的底层实现原理

volatile的底层实现原理

volatile 能保证可见性有序性,但是不保证原子性

volatile为什么不保证原子性

让一个 volatile 的integer自增(i++),其实要分成3步:1) 读取volatile变量值到local; 2) 增加变量的值;3) 把local的值写回,让其它的线程可见。这3步的jvm指令为:

mov    0xc(%r10),%r8d ; Load
inc    %r8d           ; Increment
mov    %r8d,0xc(%r10) ; Store
lock addl $0x0,(%rsp) ; StoreLoad Barrier

注意最后一步是内存屏障。

如果一个变量被volatile修饰了,那么肯定可以保证每次读取这个变量值的时候得到的值是最新的,但是一旦需要对变量进行自增这样的 非原子操作,就不会保证这个变量的原子性了。

volatile如何保证有序性

volatile 底层使用内存屏障来保证了有序性,内存屏障其实就是一个CPU指令
从硬件层面可以分为2种:Load Barrier 和 Store Barrier即读屏障和写屏障。主要有两个作用:

  1. 阻止屏障两侧的指令重排序;
  2. 强制把写缓冲区/高速缓存中的脏数据等写回主内存,让缓存中相应的数据失效。

首先一个变量被volatile关键字修饰之后有两个作用:

  1. 对于写操作:对变量更改完之后,要立刻写回到主存中。
  2. 对于读操作:对变量读取的时候,要从主存中读,而不是缓存。

volatile如何保证可见性

可见性是使用了lock锁汇编指令实现,让副本数据主动刷新主内存数据,从而实现缓存数据一致性问题
LOCK指令根据CPU的不同,存在两种机制:

  1. 总线锁
  2. MESI协议

MESI 缓存一致性协议

MESI分别代表缓存行数据所处的四种状态(使用额外的两位(bit)表示),通过对这四种状态的切换,来达到对缓存数据进行管理的目的:

状态描述监听
M 修改(Modify)该缓存行有效,数据被修改了,和内存中的数据不一致,数据只存在于本缓存行中缓存行必须时刻监听所有试图读该缓存行相对应的内存的操作,其他缓存须在本缓存行写回内存并将状态置为E之后才能操作该缓存行对应的内存数据
E 独享、互斥(Exclusive)该缓存行有效,数据和内存中的数据一致,数据只存在于本缓存行中缓存行必须监听其他缓存读主内存中该缓存行相对应的内存的操作,一旦有这种操作,该缓存行需要变成S状态
S 共享(Shared)该缓存行有效,数据和内存中的数据一致,数据同时存在于其他缓存中缓存行必须监听其他缓存是该缓存行无效或者独享该缓存行的请求,并将该缓存行置为I状态
I 无效(Invalid)该缓存行数据无效

状态之间的转换

local readlocal write分别代表本地CPU读写。
remote readremote write分别代表其他CPU读写
四种状态的变化情况

为什么单例模式的双重检查锁,对象要声明volatile?

源码如下:

public class Singleton {
	private static volatile instance = null;
	
	public static Singleton getInstance() {
        if (instance == null) {  
            synchronized (Singleton.class) {  
               if (instance == null) {  
                  Singleton.instance = new Singleton(); 
               }  
            }  
        }  
        return singleton; 
    }
}

原因如下:

  1. 因为在多线程访问到 第6行 时第二线程进入会阻塞,线程被唤醒时,检查instance变量是否为空需要保证可见性。
  2. 是为了在 第8行 防止Singleton初始化时的 指令重排序,因为初始化的步骤可以分为:
    (1)分配对象空间
    (2)调用构造函数初始化
    (3)将对象赋值给变量
    如果发生了 指令重排序,有可能会将赋值步骤重排序到调构造函数之前,那么在这时如果有线程 第5行 检查instance变量是否为空,则为false并获得了不完整的对象时,在使用过程中就可能会存在问题,所以需要加上 volatile,保证可见性和有序性。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值