CPU的运算速度非常快,不能与主内存直接进行交互,
中间加了一层高速缓存(寄存器,缓存)
java线程内存也是如此,每个线程再访问同一个共享变量的时候,他会先将此变量生成一个副本,如此线程B修改副本后,线程A并无法感知
JMM数据的原子操作(硬件级别) h
read(读取): 从主内存读取数据
load(载入):将主内存读取到的数据写入工作内存
use(使用):从工作内存读取数据来计算
assign(赋值):将计算好的值重新赋值到工作内存当中
store(存储):将工作内存数据写入主内存
white(写入):将store过去的变量值赋值给主内存中的变量
lock(锁定):将主内存变量加锁,标识为线程独占状态
unlock(解锁):将主内存变量解锁,解锁后其他线程可以锁定该变量
多线程原子操作流程图
解决相互可见性问题
1、总线加锁
在主线加锁,cpu在read之前,会进行一次lock,其他cpu会进行等待,当这个cpu运行结束之后,再进行unlock。这种方式会将并行变为串行,效率太低
2、总线(MESI缓存一致性协议)
当加了关键字volatile时,会在底层开启一个总线级别的MESI缓存一致性协议以及总线嗅探机制(监听)
当其他cpu将变量进行修改(store),其他cpu只要开启了嗅探机制, 一旦发现访问的共享变量发生变化,会将工作内存中的副本的值失效,cpu就会重新从主内存中read,这时会read最新的值
volatile关键字
保证了多线程间的变量副本的相互可见性,通过MESI缓存一致性协议完成
volatile缓存可见性实现原理
底层实现主要是通过汇编lock前缀指令,他会锁定这块内存区域的缓存,并写回到主内存
lock add dword ptr [rsp],Oh
res—>写入内存
lock前缀:1、在看到cpu进行assign(赋值)操作时,会直接将值同步回主内存、2、写会主内存的操作会引起其他cpu里缓存了该内存地址的数据,变为无效(MESI协议)
注:volatile也会进行加锁操作
当cpu进行store操作时,这时并没有进行white操作,变量还是原先的值,如果没有lock,其他cpu将会继续read到旧数据,所以在store操作之前需要lock,等write结束后在unlock