深入理解Java内存模型(JMM)
Posted 单片机菜鸟哥
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入理解Java内存模型(JMM)相关的知识,希望对你有一定的参考价值。
文章目录
纯属学习B站教学视频笔记,方便查阅
1、多核并发缓存架构
CPU高速(对应电脑上)缓存:现代CPU性能强运算速度快,而RAM速度并没有随之增长,所以如果CPU直接和RAM通信会直接拉低了CPU性能。运行程序时,把主内存RAM数据读取到CPU高速缓存,通过高速缓存和CPU进行数据交互。不过高速缓存就稍微有点贵。
2、Java内存模型(JMM,Java Memory Model)
Java线程内存模型和Cpu缓存模型类型,是基于Cpu缓存模型来建立的,Java线程内存模型是标准化的,屏蔽掉了底层不同计算机的区别。主要注意每个线程自己独立拥有的
工作内存
以及共享变量副本
。
举个错误例子:
public class VolatileVisibilityTest {
// private static volatile boolean initFlag = false; // 注意volatile可见性
private static boolean initFlag = false;
public static void main(String[] args) throws InterruptedException{
new Thread(()->{
System.out.println("waiting data...");
while(!initFlag) {
}
System.out.println("============ success");
}).start();
Thread.sleep(2000);
new Thread(()->prepareData()).start();
}
public static void prepareData() {
System.out.println("prepareData data...");
initFlag = true;
System.out.println("prepareData data end...");
}
}
3、JMM数据原子操作(干货)
通过JMM原子操作理解Java内存模型。
3.1 read —— 读取
- 从主内存读取数据
3.2 load —— 载入
- 将主内存读取到的数据写入到工作内存
3.3 use —— 使用
- 从工作内存读取数据来计算
3.4 assign —— 赋值
- 将计算好的值重新赋值到工作内存中
3.5 store —— 存储
- 将工作内存数据写入主内存
3.6 write —— 写入
- 将store过去的变量值赋值给主内存中的变量
3.7 lock —— 锁定
- 将主内存变量加锁,标识为线程独占状态
3.8 unlock —— 解锁
- 将主内存变量解锁,解锁后其他线程可以锁定该变量
4、不加volatile下的原子过程分析
以原子操作解读上面的代码。先解读没有加Volatile的代码
到这一步其实就可以看到,数据不一致(数据修改可见性)。
5、MESI缓存一致性协议
多个cpu从主内存读取同一个数据到各自的高速缓存,当其中某个cpu修改了缓存里的数据,该数据会马上同步回主内存,其他cpu通过
总线嗅探
机制可以感知到数据的变化从而将自己缓存里的数据失效
。
6、加volatile下的原子过程分析
在上面的基础上,
重新read store之后会得到新的值。
7、volatile缓存可见性实现原理(lock、unlock原子操作)
底层实现主要是通过汇编lock前缀指令,它会锁住这块内存区域的缓存(缓存行锁定)并回写到主内存。
- 会将当前处理器缓存行的数据立即写回到系统内存
- 这个写回内存的操作会引起在其他cpu缓存了该内存地址的数据无效(MESI协议)
注意一下加锁位置(加锁颗粒度考虑问题
):
8、volatile不保证原子性
private static volatile int num = 0;
多线程执行一个 num++
多个线程同一时刻做num++
要解决这个原子性问题,最终还是得在线程进行操作数据的时候做一些加锁限制。(也就是对方法加锁)
synchronized
关键字- Java.util.concurrent包中的
lock
接口和ReentrantLock
实现类
以上是关于深入理解Java内存模型(JMM)的主要内容,如果未能解决你的问题,请参考以下文章