面试必备之volatile

cpu直接有速度不匹配的问题,引入了缓存

认识volatile

程序举例:用一个线程读数据,一个线程改数据,存在数据的不一致性。

机器硬件cpu和JMM

1.cpu cache模型
image.png
cache:是一个硬件,速度快,容量小。
i 的例子可能会引起数据的不一致性。
程序的局部执行原理:把内存中的数据读到cache中—>在cache中更新数据—>把更新的结果书信到内存中去。
2.cpu缓存的一致性问题
解决方案:
1)总线加锁(粒度太大)
2)MESI协议:
a) 读操作:不做任何事情,把cache中的数据读到寄存器中
b) 写操作:发出信号通知其他的cpu将变量的cacheline置为无效,其他的cpu要访问这个变量的时候,只能从内存中获取。
3.java内存模型
主存中的数据和工作空间的交互
1)主存中的数据,所有线程都可以访问
2)每个线程都有自己的工作空间(本地内存–私有数据)
3)工作空间数据是局部变量,内存的副本
4)线程不能直接修改内存中的数据,只能读到工作空间来修改,修改完成后刷新到内存。

volatile关键字的语义分析

volatile作用:让其他线程能够马上感知到某一个线程对某个变量的修改
1.保证可见性
对共享变量的修改,其他的线程可以马上感知到;但是不能保证原子性。
2.保证有序性
重排序(编译阶段、指令优化阶段)
输入程序的代码顺序并不是实际的执行数据,重排序后对单线程没有影响,对多线程有影响

volatile规则:对于volatile修饰的变量,volatile之前的代码不能调整到他的后面;volatile之后的代码不能调整到他的前面(as-if-seria);霸道原则(位置不变化)。
3.volatile的原理和实现机制(轻量级锁)
HSDIS 反编译 汇编工具
Java—class—jvm—>ASM文件
volatile int a;是给a加三个锁lock

volatile使用场景

1.状态标志(开关模式)
2.双重检查锁定(double-checked-locking) DCL
例如单例模式
3.需要利用顺序性

volatile和synchronized区别

1.使用上的区别
volatile只能修饰变量,sync只能修饰方法和语句块。
2.对原子性的保证
sync可以保证原子性,volatile不能保证原子性。
3.对可见性的保证
都可以保证,但是实现原理不同,volatile对变量加了lock,sync使用monitorenter和monitoeexit。
4.对有序性的保证
volatile能保证有序,sync可以保证有序性,但是代价并发返回到串行(重量级)。
5.其他
sync引起阻塞。
volatile不会引起阻塞。

volatile的原理和实现机制

volatile到底如何保证可见性和禁止指令重排序的?
“观察加入volatile关键字和没有加入volatile关键字时所生成的汇编代码发现,加入volatile关键字时,会多出一个lock前缀指令”
lock前缀指令实际上相当于一个内存屏障(也成内存栅栏),内存屏障会提供3个功能:
1)它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成;
2)它会强制将对缓存的修改操作立即写入主存;
3)如果是写操作,它会导致其他CPU中对应的缓存行无效。

猜你喜欢

转载自blog.csdn.net/weixin_44006731/article/details/129331247