说实话,博主在学习JMM这块知识的时候,感觉挺费劲
其实知识点本身,什么主内存、工作内存、MESI、内存屏障都很好理解,只是会涉及到硬件和OS方面的相关知识,DDDD
但真正麻烦的是,这些零散的知识点形成不了一个体系,导致很难真正去感知JMM是一个什么东西,也就没法真正掌握他
本身JMM就是一个抽象的东西,没法具象化,不像其他锁或者GC啥的是一个具体的东西
所以我觉得学JMM之前,最好对他形成一个宏观的认知,首先搞清楚为什么要有JMM?JMM和硬件相关的知识之间有什么因果关系?
捋清整个JMM体系的脉络,再去深入学细节,由浅入深,才能更好地掌握他
本文会从宏观的角度归纳Java内存模型存在的意义
而不会详细地剖析JMM某个具体的知识点,因为随便找一个出来都够重新写一篇文章了
硬件工作效率
-
现代处理器一般都是多核的,而且为了充分利用CPU性能,会让CPU分时间片并发执行计算任务
-
但是多数运算任务不止是简单的处理器计算就能完成,还要与内存交互
而且内存的速度与CPU差了好几个数量级,所以为了解决CPU与内存速度差异过大问题,引入CPU三级cache
-
有了三级cache之后,为了充分利用CPU内部的运算单元,会对指令乱序执行处理,进行处理器优化
并发编程的问题
正是由于以上三个提高硬件工作效率的措施,才会导致在并发编程中出现数据一致(可见)性、原子性、有序性问题
数据一致性
CPU的三级cache,会导致主内存的变量值在不同核心的cache中不一致,引发并发编程时数据不一致
原子性
若代码指令没执行完,时间片就用完了,操作被迫中断,导致操作不原子
有序性
指令乱序执行,会导致程序运行后得出非预期结果
并发问题的解决
硬件层面
-
数据一致性
MESI、缓存锁、总线锁等数据一致性协议
这里为了充分利用处理器内部运算单元,可能会进行指令乱序执行,引发有序性问题
-
有序性
内存屏障
由于不同CPU实现的架构不一样,对各种并发问题的解决手段不一样,为了屏蔽底层硬件和OS对内存的访问差异
JVM定义了内存模型的规范,抽象出内存模型的概念,在不同硬件架构平台上的虚拟机对内存模型有不同的实现
保证Java并发程序在不同的平台上运行、对内存的访问都能得出相同的结果
C/C++是直接使用处理器和OS的内存模型,所以有可能在一个平台正常运行的程序到另一个平台运行就出错,所以写C/C++程序时,需要我们去关注和处理平台间的差异带来的并发问题
而Java因为有了内存模型,屏蔽掉不同平台底层解决并发问题的手段,使得进行Java并发编程时可以只关注业务的本身,而无需去关心如何解决底层并发问题
JVM层面
-
数据一致(可见)性
volatile
-
有序性
JVM内存屏障
-
原子性
锁