jmm内存模型
java线程内存和cpu缓存模型类似,是基于cpu缓存模型来建立的,java线程内存模型是标准化的,屏蔽了底层不同操作系统的差异
jmm数据原子操作
- read读取:从主内存读取数据
- load载入:将主内存数据读取到的数据写入工作内存
- use使用:从工作内存读取出数据使用
- assign赋值:将计算好的值重新赋值到工作内存中
- store存储:将工作内存数据写入主内存
- write写入:将store过去的变量赋值给主内存中的变量
- lock锁定:将主内存变量加锁,表示为线程独占状态
- unlock解锁:将主内存变量解锁,解锁后其他线程可以锁定该变量
线程运行时从主内存将共享变量读出,在工作内存中存储一份共享变量副本,之后的操作都会使用这个副本的值。这会导致多线程修改主内存变量后造成其他线程工作内存数据与主内存中数据不一致问题。
解决数据不一致问题思路:
总线加锁:cpu从主内存读取数据到高速缓存,会在总线对数据加锁,这样其他cpu线程无法读写这个数据,直到对它加锁的cpu线程运行结束释放锁后其他cpu线程才可以读取到该数据。这样导致性能明显下降。
MESI缓存一致性协议:多个cpu从主内存读取同一个数据到各自的高速缓存,当其中某个cpu修改了缓存里的数据后,该数据会马上同步回主内存,其他cpu通过总线嗅探机制可以感知到数据的变化从而将自己缓存里的数据失效。
Volatile缓存可见性实现原理
底层实现主要是通过汇编lock前缀指令,他会锁定这块内存区域的缓存(缓存行锁定)并回写到主内存
IA-32架构软件开发手册对lock指令的解释:
- 会将当前处理器缓存行的数据立即写回到系统内存。
- 这个写回内存的操作会引起在其他CPU里缓存了该内存地址的数据无效(MESI协议)
并发编程三大特性:可见性,原子性,有序性。
volatile虽然可以保证共享变量的可见性,但是无法保证其原子性,当大量线程并发操作变量时,总线嗅探机制会使某些操作失效,导致最终结果和预想不一致。