想要学好多线程,Java内存模型是必须要掌握的知识点,那么我就把我自己理解的内存模型写在这里,欢迎斧正。
我的理解:
JMM的作用我认为是用来消除计算机硬件和内存之间访问差异的。
当计算机执行命令的时候,每个数据的操作都是CPU去执行的,而数据是放在一个在主存
(可以理解为计算机的物理内存)的地方,所以呢,CPU在执行的时候,CPU的寄存器就要去频繁的操作主存中的数据:
- 从主存中读取数据到CPU执行;
- 将执行完成的数据再写入主存。
这里会有一个问题,就是CPU处理能力太快了,快到主存跟不上,所以就导致在执行周期的大部分时间都耗费在从主存中读取和写入数据这里。
为了解决这个问题,就在CPU和主存之间加了个高速缓存
的这么个东西。缓存大家都懂,速度比主存这种物理内存要快上很多,不过和物理内存相比,价格是比较昂贵的。
加上高速缓存
之后,CPU的执行逻辑就是这样子的:
当程序在运行过程中,会将运算需要的数据从主存复制一份到CPU的高速缓存当中,那么CPU进行计算时就可以直接从它的高速缓存读取数据和向其中写入数据,当运算结束之后,再将高速缓存中的数据刷新到主存当中。
再到后来,一个高速缓存已经满足不了CPU的需求了,开始衍变为多级缓存,像家用电脑这种基本都是二级缓存或者是三级缓存,在任务管理器中就可以看到,我这里是三级缓存:
一级缓存速度最高,但储存的容量最小,以此类推。
有了多级缓存之后,程序的执行逻辑就是这样的:
当CPU要读取一个数据时,首先从一级缓存中查找,如果没有找到再从二级缓存中查找,如果还是没有就从三级缓存中查找,一级一级找下去,直到从主存中找到数据
随着科技的发展,很多电脑都是多核CPU的了,也就是说,每个CPU都有自己单独的缓存,但每个CPU的缓存互相读取不到其他CPU缓存数据的,也就是说主存中的数据是共享的,CPU缓存中的数据是每个CPU私有的,在多核CPU中如果执行多线程程序的话,每个CPU都会从主存中拿到数据到自己的缓存中,然后在自己的缓存中读取数据进行执行,执行之后再刷新到主存中。这种操作就会造成数据不一致的现象。
比如说执行int = i + 1
,假设i的初始值为0,那么CPU1从主存中拿到数据之后的操作接口是1,这时还没登CPU1写回主存呢,CPU2也拿到这条缓存行的数据了,执行之后的结果还是1,这样的话两个CPU写回主存中的数据都是1,为了解决这个问题,大佬们又引入了叫缓存一致性(MESI)的东西。
缓存一致性协议(MESI):
在多核CPU中,每个CPU的缓存中都会保存主存中数据的副本,这时,当某一个CPU刷新数据到主存之后,就会产生数据不一致的问题,而缓存一致性协议的作用就是为了保存多核CPU缓存之间数据的一致性,说了这么多,简单的画了个图,大家可以看一下:
想要更详细的了解缓存一致性可以看看这篇文章:https://blog.csdn.net/xianyun1992/article/details/107743582
JMM主要就是围绕着如何在并发过程中如何处理原子性、可见性和有序性这3个特征来建立的,通过解决这三个问题,可以解除缓存不一致的问题,volatile跟可见性和有序性都有关。