Volatile和CAS(可见性、有序性、内存屏障、MESI)解析
2021-03-02 16:10:07 0 举报
AI智能生成
Volatile+CAS(可见性/有序性/内存屏障/MESI)
作者其他创作
大纲/内容
阅读导航
线程 👉
CPU+JMM 👉
CAS+Volatile
Synchronized 👉
JUC 👉
线程池 👉
ThreadLocal 👉
CAS
CAS是一种自旋操作,有3个操作数,变量v,期待值a,修改值b,当a=v时,将变量值修改为b,否则什么都不做
Compare and Swap:比较并交换
底层原理是sum.misc.Unsafe类,调用native方法实现
在系统的最底层CPU指令支持:lock cmpxchg
在系统的最底层CPU指令支持:lock cmpxchg
cmpxchg:CPU级别的CAS操作,非原子性
lock:多核CPU时,采用类似总线锁来完成CAS
lock指令在执行后面指令的时候锁定一个北桥信号
缺点
ABA问题
使用时间戳或版本号机制
只能保证一个共享变量的原子操作
如果CAS一直不成功会给CPU带来很大开销
应用:Atomic包
volatile
可见性
主要解决线程间共享变量的可见性和有序性
线程在对volatile修饰的变量 执行写操作时会立刻把写入的值刷新到主内存,同时使副本失效
① happen-before
对于两个操作 A 和 B,这两个操作可以在不同的线程中执行。如果 A Happens-Before B
那么可以保证,当 A 操作执行完后,A 操作的执行结果对 B 操作是可见的(8种规则之一)
那么可以保证,当 A 操作执行完后,A 操作的执行结果对 B 操作是可见的(8种规则之一)
原理:执行写操作的时候JVM会给CPU发送一条 lock前缀指令
CPU会立即将这个值写回主内存(总线锁)
同时使其他CPU缓存中的副本失效(触发MESI)
② MESI:缓存一致性协议
原理:各个CPU会对总线进行嗅探,如果发现有人修改了某个缓存的数据,那么CPU就会
将自己本地的缓存过期掉,再次读取那个变量的时候,就会从主内存重新加载最新的数据
将自己本地的缓存过期掉,再次读取那个变量的时候,就会从主内存重新加载最新的数据
MESI是四种修饰缓存行的四种状态的缩写,详细分析见上一小节(CPU架构)👉
有序性
内存屏障
禁止指令重排
禁止指令重排
内存屏障其实也是一种JVM指令,Java内存模型的重排规则会要求Java编译器在生成
JVM指令时插入特定的内存屏障指令,通过这些内存屏障指令来禁止特定的指令重排序
JVM指令时插入特定的内存屏障指令,通过这些内存屏障指令来禁止特定的指令重排序
四种类型
LoadLoad:保证load1的读取操作在load2及后续读取操作之前执行
LoadStore:在stroe2及其后的写操作执行前,保证load1的读操作已读取结束
StoreLoad:保证store1的写操作已刷新到主内存之后,load2及其后的读操作才能执行
StoreStore:在store2及其后的写操作执行前,保证store1的写操作已刷新到主内存
不保证原子性
如果一个变量被volatile修饰了,那么肯定可以保证每次读取这个变量值的时候得到的值是
最新的,但是一旦需要对变量进行自增这样的非原子操作,就不会保证这个变量的原子性
最新的,但是一旦需要对变量进行自增这样的非原子操作,就不会保证这个变量的原子性
解决
加锁
AtomicInteger原子类
应用
单例模式的懒汉式(double-check)
适合只有一个线程修改,其他线程读取的情况
比如作为状态位,A线程调用了某个方法让B线程感知
关于作者
我的博客 👉
微信公众号 👉
GitHub 导航 👉
ProcessOn 主页 👉
0 条评论
下一页