内存模型
内存模型:在特定的操作协议下,对特定的内存或者高速缓存进行读写访问的过程抽象
定义了共享内存多核系统中多线程程序读写操作行为的规范。通过实现这些规范的规则来对内存进行读写,以保证指令执行的正确性,它解决了CPU多级缓存、处理器优化、指令重排序等导致的内存访问问题
Java内模型
Java内存模型:一种符合内存模型规范的,屏蔽了各种硬件和操作系统差异(write once,run anywhere),保证Java程序在各种平台下对内存的访问都能保证效果一致的机制和规范。它的主要目的是定义程序中各种变量的访问规则,关注的是在虚拟机中如何把变量值存储到内存和从内存中取出变量值的细节(变量:特指共享的数据,而不包括局部变量等线程私有数据)
- JMM规定所有的变量都存储在主存中,线程的工作内存保存了本该线程使用的变量的副本(不是将主存中的整个变量都copy一份到工作内存中,只是使用到的属性值)
- JMM规定线程对变量的所有操作都必须在工作内存中进行,线程不能直接读写主存的数据,线程之间的工作内存相互独立,线程间的通信通过主存完成
一段经典代码:线程A执行foo方法,线程B执行bar方法,为什么有时候assert断言失败,为什么b被volatile修饰之后,断言能一直成功
int a=0;
// volatile int b = 0;
int b=0;
void foo() {
a = 1;
b = 1;
}
void bar() {
while (b == 0)
continue;
assert(a == 1)
}
八大指令
JMM 定义了8个指令用于实现如何把一个变量中主存拷贝到工作内存和如何把工作内存中的数据同步回主存,JVM实现时必须保证每一个指令都是原子性的
- lock:作用于主存,把一个变量标识成被一条线程独占的状态
- unlock:作用于主存,把处于锁定状态的变量进行释放
- read:作用于主存,把主存变量的值从主存传输到线程的工作内存中,待load使用
- load:作用于工作内存,将read操作从主存得到的变量值,放到线程对应的工作内存中
- use:作用于工作内存,把工作内存中的一个变量的值传递给执行引擎,每当虚拟机遇到一个需要使用变量的值的字节码指令时就是执行use操作
- assign(赋值):作用于工作内存,把工作内存中的一个变量的值赋给工作内存中的变量
- store:作用于工作内存,把工作内存中变量的值传到主存中,供之后的write使用
- write:作用于主存,把store操作传输到主存中的变量放到主存的变量中
把一个变量从主存拷贝到工作内存:read -> load
把一个变量从工作内存同步到主存:store->write
八大指令的执行要求
- 不允许read和load、store和write操作单一出现,必须成对出现
- 不允许先丢弃它最近的assign操作,变量在工作内存改变之后,必须把该变化同步到主存
- 一个变量同一时刻只允许一个线程对其进行lock操作,lock操作可以被同一个线程重复执行多次(类似于可重入锁),多次lock,就需要同样次数的unlock,变量才会被解锁
- 如果一个变量事先没有被lock操作锁定,那就不允许对它执行unlock操作,也不允许去unlock一个 被其他线程锁定的变量
- 如果对一个变量进行lock操作,那将会清空工作内存中此变量的值,在执行引擎使用这个变量前,必须重新执行load或assign操作初始化这个变量的值(简单