深入再深入volatile关键字
众所周知volatile关键字可以实现不同线程之间对于共享变量的可见性,先来两张本人的灵魂画图
那么volatile是怎么实现线程之间数据的可见性的呢?
(细心的小伙伴可能发现volatile的源码不是用java实现的)
先附上 JMM数据原子性操作:
lock(锁定):作用于主内存变量,把一个变量标识为一条线程独占状态。
unlock(解锁):作用于主内存变量,把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定。
read(读取):作用于主内存变量,把一个变量从主内存传输到线程的工作内存中,以便随后的 load 动作使用。
load(载入):作用于工作内存变量,把 read 操作从主内存中得到的变量值放入工作内存的变量副本中。
use(使用):作用于工作内存变量,把工作内存中的一个变量值传递给执行引擎,每当虚拟机遇到一个需要使用变量值的字节码指令时执行此操作。
assign(赋值):作用于工作内存变量,把一个从执行引擎接收的值赋值给工作内存的变量,每当虚拟机遇到一个需要给变量进行赋值的字节码指令时执行此操作。
store(存储):作用于工作内存变量,把工作内存中一个变量的值传递到主内存中,以便后续 write 操作。
write(写入):作用于主内存变量,把 store 操作从工作内存中得到的值放入主内存变量中。
对于JMM缓存不一致的问题的解决方案如下:
总线加锁(由于性能低,已经弃用)
cpu从主内存读取数据到高速缓存,会在读取前对这个数据加锁,这样其它cpu没法去读或写这个数据,直到cpu释放锁才可以读或者写。 如图:
上图中线程B在读取数据前对主存中的singFlag数据lock(加锁),此时线程A只能等待,随后线程B修改数据后写入主存中,最后执行unlock(释放锁)操作,然后线程A才能进行读写操作。
MESI缓存一致性协议
多个cpu从主内存读取同一个数据到各自的高速缓存,当其中某个cpu修改了缓存里的数据,该数据会马上同不会主内存,其他cpu通过总线嗅探机制可以感知到数据的变化从而将自己缓存里的数据失效。 如图:
上图中线程B修改数据后在写入时执行lock操作(可以理解为在总线上加锁,此处牵扯到物理层知识不展开说),加锁后别的线程通过总线嗅探机制发现数据已经加锁,就会迅速把自己的数据失效掉,失效后此数据必须在主存中从新获取(注意:每个cpu都有一个总线嗅探的机制),然后线程B写入数据到主存中,此时执行unlock操作,线程A从新获取数据
对于JMM缓存不一致的问题,两种解决方案的比较:
MESI缓存一致性协议方案的粒度更小,耗时更短。
注:喜欢的小伙伴可以支持一下啊 -^- ,如有建议不胜荣幸!
以上总结部分均为作者原创,版权归作者本人所有,如侵犯到原作者权益,请与我们联系删除