JMM内存模型
java多线程内存模型跟CPU缓存模型类似,是基于CPU缓存模型来建立的,java线程内存模型是标准化的,屏蔽掉了底层不同计算机的区别
![](https://i-blog.csdnimg.cn/blog_migrate/5367e8f794a056c4e1699c7fa6d73a97.png)
实例代码:
实例结果
如果没有加volatile则结果为
JMM数据原子操作
- read(读取):从主内存读取数据
- load(载入):将主内存读取到的数据写入工作内存
- use(使用):从工作内存读取数据来计算
- assign(赋值):将计算好的值重新赋值到工作内存中
- store(存储):将工作内存数据写入主内存
- write(写入):将store过去的变量值赋值给主内存中的变量
- lock(锁定):将主内存变量加锁,标识为线程独占状态
- unlock(解锁):将主内存变量解锁,解锁后其他线程可以锁定该变量
主要是形容数据在主内存以及工作内存线程内部相互之间交互、交换的一些原子操作
JMM缓存不一致问题
- 缓存一致性 协议(MESI)
多个CPU从主内存读取同一个数据到各自的高速缓存,当其中某个CPU修改了缓存里的数据,该数据会马上同步回主内存,其他CPU通过总线嗅探机制可以感知到数据变化从而将自己缓存里的数据失效
- 缓存加锁
缓存锁的核心机制是基于缓存一致性协议来实现的,一个处理器的缓存回写到内存会导致其他处理器的缓存无效,IA-32和Intel 64处理器使用MESI实现缓存一致性协议
![](https://i-blog.csdnimg.cn/blog_migrate/9004eb0b4de00e878a738b450ed9501f.png)
Volatile可见性底层实现原理
- Volatile缓存可见性实现原理
底层实现主要是通过汇编lock前缀指令,它会锁定这块内存区域的缓存(缓存行锁定)并回写到主内存
IA-32和Intel 64架构软件开发手册对lock指令的解释:
- 会将当前处理器缓存行的数据立即回写到系统内存
- 这个回写内存的操作会引起其他CPU里缓存了该内存地址的数据无效(MESI协议)
- 提供内存屏障功能,使lock前后指令不能重排序
- Java程序汇编代码查看
-server -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly-XX:CompileCommand=compileonly,*VolatileVisibilityTest.prepareData
指令重排序与内存屏障
- 并发编程三大特性:可见性,有序性,原子性
- Volatile保证可见性与有序性,但是不保证原子性,保证原子性需要借助synchronized这样的锁机制
- 指令重排序:在不影响单线程程序执行结果的前提下,计算机为了最大限度的发挥机器性能,会对机器指令重排序优化
- 重排序会遵循as-if-serial与happens-before原则