java内存模型
Java内存模型即Java Memory Model,简称JMM。JMM定义了Java 虚拟机(JVM)在计算机内存(RAM)中的工作方式。JVM是整个计算机虚拟模型,所以JMM是隶属于JVM的,JMM是java虚拟机内存管理规范。
JMM和硬件的关系
线程,工作内存,主内存工作交互图(基于JMM规范)
主内存
主要存储所有线程创建的实例对象,包括实例对象的成员变量和本地变量
工作内存
每一个线程所独立的一个工作区间,该区间只是对该线程所独有,不对其他线程所可见。当cpu切换时间片执行对应的线程事,该线程的工作区间会从主内存中拷贝一份数据放到工作内存中,供该线程做执行,执行完操作之后,cpu会将工作内存中的数据刷新到主内存中去,当存在多个线程对一个主内存中的同一数据进行操作的,会存在数据安全性的问题。
硬件关系
jvm内存模型和计算机硬件之间没有必然的联系,计算机硬件存储只要有主内存,cpu一级或者多级缓存,寄存器,jmm中的定义的工作内存和主内存都存在于硬件的主内存中,所以JMM是一种规范,是一个约束模型。
java多线程执行是会存在安全性问题,例如在这里插入代码片
Thread t1 =
private volatile static int x = 0, y = 0;
private static int a = 0, b = 0;
new Thread(new Runnable() {
public void run() {
shortWait(10000);
a = 1;
x = b;
// UnsafeInstance.reflectGetUnsafe().fullFence();
}
});
Thread t2 = new Thread(new Runnable() {
public void run() {
b = 1;
// UnsafeInstance.reflectGetUnsafe().fullFence();
y = a;
}
});
上述代码比较简单,可以通过简单的分析就可以得到x和y存在的几种情况
x | y | 原因 |
---|---|---|
0 | 1 | 顺序执行,先执行t1,执行完成之后执行t2 |
1 | 0 | 顺序执行,先执行t2,执行完成之后执行t1 |
1 | 1 | 先执行t1,赋值a=1之后,cpu去换执行t2,t1等待,t2执行完之后,在继续执行t1 |
0 | 0 | 指令重排导致的问题,后续说明 |
代码执行之后产生较大的不确定性,所以需要进行数据的同步操作
数据同步八大原子操作
(1)lock(锁定):作用于主内存的变量,把一个变量标记为一条线程独占状态
(2)unlock(解锁):作用于主内存的变量,把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定
(3)read(读取):作用于主内存的变量,把一个变量值从主内存传输到线程的工作内存中,以便随后的load动作使用
(4)load(载入):作用于工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中
(5)use(使用):作用于工作内存的变量,把工作内存中的一个变量值传递给执行引擎
(6)assign(赋值):作用于工作内存的变量,它把一个从执行引擎接收到的值赋给工作内存的变量
(7)store(存储):作用于工作内存的变量,把工作内存中的一个变量的值传送到主内存中,以便随后的write的操作
(8)write(写入):作用于工作内存的变量,它把store操作从工作内存中的一个变量的值传送到主内存的变量中
如果要把一个变量从主内存中复制到工作内存中,就需要按顺序地执行read和load操作,如果把变量从工作内存中同步到主内存中,就需要按顺序地执行store和write操作。但Java内存模型只要求上述操作必须按顺序执行,而没有保证必须是连续执行。