简单了解volatile如何解决可见性

volatile是Java的一个关键字,是轻量级的synchronized,用于修饰变量,解决了变量没有可见性和有序性的问题,那什么是变量的可见性和有序性?首先我们先要研究操作系统层面的CPU的缓存一致性问题(对应可见性)和指令优化重排问题(对应有序性),JMM把这些问题封装成了一些关键字(如volatile、synchronized)或者API,我们直接调用就可以解决掉这些问题。

CPU的缓存和主存之间的数据一致性问题

首先要谈谈操作系统层面的可见性,也就是CPU和主存之间的缓存一致性的问题,CPU访问数据有局部性,使用缓存可以加快CPU读写数据的速度,但是同时可能造成CPU的缓存和主存之间的数据一致性问题

image-20240303214839007

CPU缓存和主存之间的缓存一致性问题主要有以下原因造成:

  • CPU之间无法同步:当某个CPU修改了主存的数据之后,其它的CPU是不知道的,还是用的是自己内部过期的缓存

  • 并发问题:当两个或者更多的CPU需要同时读写主存的时候,没有控制并发的机制存在,可能造成读写顺序反过来,导致读取到旧值

基于总线解决CPU缓存一致性

只需要在CPU和主存之间加上一条总线,通过总线就可以通知到其它CPU自己对主存数据的改动,CPU想要和主存交互来读写数据必须要经过总线,获取到总线的控制权(加总线锁)之后才能和主存进行交互。

总线嗅探

针对上文的第一个问题,我们需要研究如何让其它的CPU知道自己对于某个共享数据的修改呢?可以想到我们可以通过总线对其它CPU进行通知,在自己修改了某个共享数据之后,将新的缓存数据同步到主存的同时,通知其它的CPU该数据已经被修改,那么其他的CPU就会把这个数据缓存行设置为无效状态,下次想要读取或者修改数据之前,都需要先到主存获取到最新的数据再进行自己的操作。

总线风暴

当很多线程都共享同一个变量,并且变量被volatile修饰或者用到了CAS修改变量的值,总线上会产生大量的通信来通知相应的CPU将相应的缓存行置为无效状态,这就是总线风暴。

总线仲裁

针对上文的第二个问题,我们需要研究如何两个及以上的CPU共同修改缓存数据的时候不产生并发问题呢?当然简单的办法就是对这个共享资源上锁,当一个CPU对共享资源上锁之后,其它的CPU只能等待锁释放才能访问共享资源,自然不存在并发问题,总线仲裁就是以一定的优先算法仲裁哪个应获得对总线的使用权(那个CPU能上锁成功)。

image-20240303215406322

如何优化总线的使用

总线性能瓶颈在于基于在总线与主存打交道会造成阻塞,那么反过来想如果不通过总线与内存发生数据交互就可以避免总线加锁:

  • 先考虑从其它缓存读取而不是从主存读取:当自己的缓存行数据没有或者无效,我们向总线发起读事务,某个CPU监听到我们的需求,会把它的最新数据放到总线(既然有数据,一定是最新的,因为其它的CPU的缓存行会被总线嗅探通知为无效状态),然后我们把新的缓存行数据拷贝到自己的缓存行

  • 当其它CPU请求数据才把自己的最新数据同步到主存:有点类似于懒加载机制,当别的CPU不需要访问这个数据的时候,CPU和主存的数据不一致也没有问题,当别的CPU需要访问这个数据,也是通过前面一小点的方式将数据缓存行同步给其它的CPU,同时将最新数据同步到主存

总结:读事件优先在其它缓存读,除非其他缓存都没有最新数据;写事件只有在其它CPU也需要这个数据的时候才去获取总线锁把最新数据同步到主存

MESI协议

CPU之间没办法直接通信,所以它们之间就必须商定一套机制,如何通过自己的数据状态就能知道其他CPU的缓存情况从而做出对应的策略,而这套机制就是缓存一致性协议,MESI协议很好的优化了CPU和主存交互效率低的问题

E(独占):这个数据只有自己的缓存行有

S(共享):先考虑从其它缓存读取而不是从主存读取,这个时候就会把自己的缓存行同步到其它

M(修改):这个状态表示还有其它CPU有旧的缓存行,我们需要通过总线通信告知其它CPU设置缓存行无效状态

I(无效):这时自己需要从其它缓存或者主存获取到最新的数据

总结

CPU和主存缓存一致性的解决方案是加个总线

  • 通过总线可以在CPU间通过通信同步缓存状态;

  • 并且通过总线锁限制和主存的交互,避免并发问题。

相应的总线锁也会带来一些效率低的问题,我们需要尽量少的使用总线,那么需要有一个MESI协议辅助,通过自己的数据状态就能知道其他CPU的缓存情况从而做出对应的策略:

  • 先通过独占或者共享状态的缓存同步自己的缓存状态,否则才需要通过总线锁和主存交互;

  • 只有在别的CPU需要数据的时候才把自己的修改状态的缓存通过总线锁同步到主存。

  • 35
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值