java内存模型(Java Memory Model,JMM)是java虚拟机规范定义的,用来屏蔽掉java程序在各种不同的硬件和操作系统对内存的访问的差异,这样就可以实现java程序在各种不同的平台上都能达到内存访问的一致性。可以避免像c++等直接使用物理硬件和操作系统的内存模型在不同操作系统和硬件平台下表现不同,比如有些c/c++程序可能在windows平台运行正常,而在linux平台却运行有问题。
MESI缓存协议
CPU高速缓存(Cache Memory)
CPU为何要有高速缓存?
CPU在摩尔定律的指导下以每18个月翻一番的速度在发展,然而内存和硬盘的发展速度远远不及CPU。这就造成了高性能能的内存和硬盘价格及其昂贵。然而CPU的高度运算需要高速的数据。为了解决这个问题,CPU厂商在CPU中内置了少量的高速缓存以解决I\O速度和CPU运算速度之间的不匹配问题。
在CPU访问存储设备时,无论是存取数据抑或存取指令,都趋于聚集在一片连续的区域中,这就被称为局部性原理
。
* 时间局部性(Temporal Locality):如果一个信息项正在被访问,那么在近期它很可能还会被再次访问。比如循环、递归、方法的反复调用等。
* 空间局部性(Spatial Locality):如果一个存储器的位置被引用,那么将来他附近的位置也会被引用。比如顺序执行的代码、连续创建的两个对象、数组等。
带有高速缓存的CPU执行计算的流程
1.程序以及数据被加载到主内存
2.指令和数据被加载到CPU的高速缓存
3.CPU执行指令,把结果写到高速缓存
4.高速缓存中的数据写回主内存
多核CPU多级缓存一致性协议MESI
多核CPU的情况下有多个一级缓存,如何保证缓存内部数据的一致,不让系统数据混乱。这里就引出了一个一致性的协议MESI。如下图:
MESI协议缓存状态
缓存行(Cache line):缓存存储数据的单元
1.M
:修改,该Cache line有效,数据被修改了,和内存中的数据不一致,数据只存在于本Cache中
2.E
:独占,该Cache line有效,数据和内存中的数据一致,数据只存在于本Cache中。
3.S
:共享,该Cache line有效,数据和内存中的数据一致,数据存在于很多Cache中。
4.I
:无效,该Cache line无效。
JMM-8大原子操作
物理机高速缓存和主内存之间的交互有协议,同样的,java内存中线程的工作内存和主内存的交互是由java虚拟机定义了如下的8种操作来完成的,每种操作必须是原子性的。java虚拟机中主内存和工作内存交互,就是一个变量如何从主内存传输到工作内存中,如何把修改后的变量从工作内存同步回主内存。
1.lock
(锁定):作用于主内存的变量,把一个变量标记为一条线程独占状态
2.unlock
(解锁):作用于主内存的变量,把一个处于锁定状态的变量释放出来,释放后变量才可以被其他线程锁定
3.read
(读取):把一个变量值从主存传输到线程的工作内存中,以便随后的load动作使用
4.load
(载入):它把read操作从主内存中得到的变量值放入工作的变量副本中
5.use
(使用):把工作内存中的一个变量值传递给执行引擎
6.assign
(赋值):它把一个从执行引擎接收到的值赋给工作内存中的变量
7.store
(存储):把工作内存中的一个变量的值传送到主存中
8.write
(写入):把store操作从工作内存中的一个变量的值传送到主内存的变量中
假设执行以下代码:
var flag = false
//线程1
Thread {
if (flag) {......}
}
//线程2
Thread {
flag = true
}
以线程2为例,具体步骤:
1、执行read操作,将数据从主内存传输到线程的工作内存
2、执行load操作,主内存中得到的变量值放入工作内存的变量副本中
3、执行use操作,工作内存中的变量值传递给执行引擎
4、执行assign操作,把从执行引擎接收到的值赋给工作内存中的变量
5、执行store操作,把工作内存中的变量的值传送到主存中
6、执行write操作,把store操作从工作内存中传送的变量值更新主内存的变量中
如下图: