【并发编程学习篇】多线程并行的场景的可见性的问题分析

一、为什么多线程并行的场景会有可见性的问题?

  1. 这个问题主要是CPU为了提高运算效率,设置 三级缓存模型 带来了缓存不一致的问题
  2. 现在的计算机基本都是多核的,线程可能运行在不同的处理器下,每个线程运行的时候都需要将主内存的数据load到各自的处理器中
  3. 当一个线程对共享变量的修改,其他线程 无法立刻感知 到其他处理器对共享变量的修改,所以 缓存一致性问题就导致多线程间共享变量的可见性问题

二、volatile的作用是什么?是如何保证可见性的?

  1. volatile修饰的变量会自动加上一个lock前缀指令(汇编层面),执行的时候识别到这个指令以后,在一些比老的处理器会直接触发 总线锁,现在的话一般都是会优先触发 缓存一致性协议(缓存锁定),来保证多线程多共享变量的可见性

  2. 缓存一致性协议里缓存行会有四种状态,分别是 修改独占共享失效

  3. 首先,在缓存行的共享状态的时候,如果处理器对共享变量执行写操作的时候会对其所在缓存行加锁,同时会发一个 总线写的信号

  4. 然后,其他也拥有这个缓存行数据的处理器通过 总线窥探机制 窥探到这个信号后首先会判断自己的CPU Cache中是否也存在这个缓存行数据,如果存在的话,会把这个缓存数行据置为失效状态,然后下次读取时,直接从主内存读取

  5. 如果两个处理器 同时 对同一个缓存行的共享变量执行了写操作,然后两个处理器同一时刻都发了总线写的信号,这个时候,总线就会通过 总线裁决 的方式判断只有一个请求成功,另一个信号直接丢弃,缓存置为失效,然后下次读取时,直接从主内存读取

  6. 一个缓存行默认是 64byte,缓存的数据比这个大的话就会换 总线锁

  7. 总线锁是锁定 CPU的总线,从而导致 同一时刻 只能有一个线程与内存通信,这就避免了多线程并发造成的可见性问题

  8. 总线锁会导致锁定期间,其他处理器也不能操作其他内存地址的数据,CPU的执行效率大幅度下降,相当于单核执行 。

注意:总线裁决的执行是非常快的,只需要判断一下即可

三、缓存一致性协议的实现原理怎样的?

缓存一致性协议是通过总线窥探 的方式实现,而总线窥探又分为 窥探失效窥探更新,MESI则属于窥探失效类型

3.1 MESI缓存一致性协议中,缓存行有4种不同的状态

已修改Modified (M):缓存行是脏的(dirty),与主存的值不同。如果别的CPU内核要读主存这块数据,该缓存行必须回写到主存,状态变为共享(S).

独占Exclusive (E):缓存行只在当前处理器的缓存中,当别的缓存读取它时,状态变为共享;当前写数据时,变为已修改状态。

共享Shared (S):缓存行也存在于其它处理器的缓存中且是未修改的。缓存行可以在任意时刻抛弃。

无效Invalid (I):缓存行是无效的

3.2 窥探失效

  1. 当一个处理器将共享变量从缓存写回主内存的时候,同时会发一个 总线写的信号
  2. 其他处理器窥探到这个信号以后,会判断缓存里是否存在这个共享变量,如果存在的话,则将缓存置为 失效状态,重新从主内存读取数据

3.3 窥探更新

  1. 当一个处理器将共享变量从缓存写回主内存的时候,会将写数据 广播到总线上的所有缓存中,其他处理器缓存的所有共享副本都会窥探到这个写信号,然后 更新本地缓存数据
  2. 这个方法将写数据,通过 总线广播 给其他处理器。
  3. 它比窥探失效协议引起更大的总线流量。这就是为什么这种方法不常见。Dragon和firefly协议属于此类别。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Java学习者柯十一

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

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

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

打赏作者

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

抵扣说明:

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

余额充值