面试题:volatile可见性和防止指令重排原理

volatile的原理

底层原理

大家都知道,volatile可以保证可见性,一个线程对共享变量值的修改,能够及时同步到主内存,被其他线程看到。

除此之外,volatile 还可以防止指令重排序,原理是什么呢?

一、可见性

1.什么是可见性

        可见性:在JAVA规范中是这样定义的:java编程语言允许线程访问共享变量,为了确保共享变量能被准确和一致地更新,线程应该确保通过排他锁单独获得这个变量。通俗的将就是如果有一个共享变量N,当有两个线程T1、T2同时获取了N的值,T1修改N的值,而T2读取N的值。那么可见性规范要求T2读取到的必须是T1修改后的值,而不能在T2读取旧值后T1修改为新值。     

        volatile关键字修饰的共享变量可以提供这种可见性规范,也叫做读写可见。那么底层实现是如何通过机制保证volatile变量读写可见的?

2.原理

        首先编译之后Java代码会被编译成字节码.class文件,在运行时会被加载到JVM中,JVM会将.class转换为具体的CPU执行指令,CPU加载这些指令逐条执行。

        以多核CPU为例(两核),我们知道CPU的速度比内存要快得多,为了弥补这个性能差异,CPU内核都会有自己的高速缓存区,当内核运行的线程执行一段代码时,首先将这段代码的指令集进行缓存行填充到高速缓存,如果非volatil变量当CPU执行修改了此变量之后,会将修改后的值回写到高速缓存,然后再刷新到内存中。如果在刷新会内存之前,由于是共享变量,那么CORE2中的线程执行的代码也用到了这个变量,这是变量的值依然是旧的。    

        volatile关键字就会解决这个问题的,如何解决呢,首先被volatile关键字修饰的共享变量在转换成汇编语言时,会加上一个以lock为前缀的指令,当CPU发现这个指令时,立即做两件事:

        1.将当前内核高速缓存行的数据立刻回写到内存;

        2.使在其他内核里缓存了该内存地址的数据无效。

        第一步很好理解,第二步如何做到呢?

        MESI协议:在早期的CPU中,是通过在总线加LOCK#锁的方式实现的,但这种方式开销太大,所以Intel开发了缓存一致性协议,也就是MESI协议,该解决缓存一致性的思路是:当CPU写数据时,如果发现操作的变量是共享变量,即在其他CPU中也存在该变量的副本,那么他会发出信号通知其他CPU将该变量的缓存行设置为无效状态。当其他CPU使用这个变量时,首先会去嗅探是否有对该变量更改的信号,当发现这个变量的缓存行已经无效时,会从新从内存中读取这个变量。

3.优缺点

        volatile的好处:从底层实现原理我们可以发现,volatile是一种非锁机制,这种机制可以避免锁机制引起的线程上下文切换和调度问题。因此,volatile的执行成本比synchronized更低。

        volatile的不足:使用volatile关键字,可以保证可见性,但是却不能保证原子操作。

◆ ◆ ◆  ◆ ◆

二、指令重排 

1. 字节码层面 

添加 ACC_VOLATILE 

2. JVM层面 

volatile内存区的读写 都加屏障

  1. LoadLoad屏障:对于这样的语句Load1; LoadLoad; Load2, 在Load2及后续读取操作要读取的数据被访问前,保证Load1要读取的数据被读取完毕。 

  2. StoreStore屏障:对于这样的语句Store1; StoreStore; Store2, 在Store2及后续写入操作执行前,保证Store1的写入操作对其它处理器可见。 

  3.  LoadStore屏障:对于这样的语句Load1; LoadStore; Store2, 在Store2及后续写入操作被刷出前,保证Load1要读取的数据被读取完毕。

  4. StoreLoad屏障:对于这样的语句Store1; StoreLoad; Load2, 在Load2及后续所有读取操作执行前,保证Store1的写入对所有处理器可见。

3. 硬件层面 

硬件内存屏障 X86 

sfence: store| 在sfence指令前的写操作当必须在sfence指令后的写操作前完成。 

lfence:load | 在lfence指令前的读操作当必须在lfence指令后的读操作前完成。 

mfence:modify/mix | 在mfence指令前的读写操作当必须在mfence指令后的读写操作前完成。 

原子指令,如x86上的”lock …” 指令是一个Full Barrier,执行时会锁住内存子系统来确保执行顺序,甚至跨多个CPU。

Software Locks通常使用了内存屏障或原子指令来实现变量可见性和保持程序顺序。

◆ ◆ ◆  ◆ ◆

关注并后台回复 “面试” 或者  “视频”,

即可免费获取最新2019BAT

大厂面试题和大数据微服务视频

您的分享和支持是我更新的动力

·END·

后端开发技术

追求技术的深度

微信号:后端开发技术

觉得不错“在看”支持一下~ 

↓↓↓

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

后端开发技术

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值