1. 前言
在深入理解并发编程的过程中,针对JMM 与 锁机制的理解的逐渐深入,导致有各方面的疑问。本文从CPU缓存模型和运行机制,JMM模型和运行机制、锁的字节码文件结构入手,逐渐演变和解释,并做系统性记录。
在初步学习过程中,可能会陷入CPU缓存模型、JMM内存模型、JVM虚拟机模型之间的联系思维误区,其实没有啥关系!
JMM模型可以理解是借鉴于CPU缓存模型创建的一套JAVA多线程编程规范
。由于设计思路相似,都会存在变量一致性问题,在CPU缓存模型中使用的缓存一致性协议
去解决,而JMM中定义了八种同步操作
去解决。
文章内容如有不严谨或有误之处敬请谅解,同时欢迎大佬评论指正,ღ( ´・ᴗ・` )比心。
2. 几张重要的模型图
-
CPU缓存模型
CPU缓存模型
- 为什么会有
CPU缓存模型
?
答:
我们的程序运行在操作系统之上,操作系统屏蔽了底层硬件的操作细节,将各种硬件资源虚拟化。于是,操作系统也就同样需要解决内存缓存不一致性问题。操作系统通过 内存模型(Memory Model) 定义一系列规范来解决这个问题。无论是 Windows 系统,还是 Linux 系统,它们都有特定的内存模型。 - 什么是MESI 协议?
答:
为解决多核CPU下变量缓存一致性问题,其实是 CPU Cache 的有限状态机,一共有 4 个状态
M(Modified,已修改):
表明 Cache 块被修改过,但未同步回内存;
E(Exclusive,独占):
表明 Cache 块被当前核心独占,而其它核心的同一个 Cache 块会失效;
S(Shared,共享):
表明 Cache 块被多个核心持有且都是有效的;
I(Invalidated,已失效):
表明 Cache 块的数据是过时的。 - 指令重排序原因
JMM对底层尽量减少约束,使其能够发挥自身优势。因此,在执行程序时,为了提高性能,编译器和处理器常常会对指令进行重排序。
Store Buffer的延迟写入是重排序的一种,称为内存重排序(Memory Ordering)。除此之外,还有编译器和CPU的指令重排序。
-
编译器重排序
。
对于没有先后依赖关系的语句,编译器可以重新调整语句的执行顺序。 -
CPU指令重排序
。
在指令级别,让没有依赖关系的多条指令并行。 -
CPU内存重排序
。
CPU有自己的缓存,指令的执行顺序和写入主内存的顺序不完全一致。
CPU处理器重排序原因。
出自《现代操作系统(第三版)中文版》
CPU指令重排序
- 缓存行
定义:
缓存系统最小的存储单元,主流大小64字节 - 缓存行伪共享问题:
定义:
多线程修改互相独立的变量时,如果这些变量共享同一个缓存行,就会无意中影响彼此的性能,这就是伪共享
解决办法:
1)让不同线程操作的对象处于不同的缓存行。
2)使用编译指示,强制使每一个变量对齐。
jvm启动时设置-XX:-RestrictContended & JDK8 使用@sun.misc.Contended
-
JMM(JAVA Memory Model)
JAVA内存模型 -
JMM模型执行过程
JAVA内存模型执行流程
转自:JMM内存模型八大原子性操作 -
JVM虚拟机结构
JDK8 JVM虚拟机结构
转自: Java内存区域详解