JVM定义了一种内存模型(Java Memory Model)来屏蔽各种硬件和操作系统的内存访问差异。以实现让Java在各种平台下都能达到一致的内存访问效果。
主内存与工作内存
Java内存模型的主要目标是
定义程序中各个变量的访问规则
也就是说在JVM中将变量存储到内存和从内存读取变量的底层细节。当然这里变量(实例字段、静态字段、数组对象元素),不包括局部变量和方法参数,因为这两者是私有的,不会被线程共享。
至于主内存和工作内存,我们看一张图就可以明白它们之间的关系:
从这张图中可以看到工作内存和主内存
Java内存模型规定所有的变量都存储在主内存中,每个线程都有自己的工作内存,工作内存里面存的是该线程所用到的变量的主内存副本的拷贝。线程对变量的所有操作都在工作内存中进行,而无法直接访问主内存。不同的线程之间也无法直接访问其他线程的工作内存中的变量,线程间变量值的传递均需通过主内存来完成。
内存间的交互操作
在上面提到,一个线程无法直接访问主内存,只能通过工作内存,那么主内存和工作内存之间如何交互?Java内存模型中定义了如下8种操作来完成。JVM实现时必须保证每一种操作都是原子的、不可再分的。
- lock(锁定):作用于主内存的变量,把一个变量标识为一个线程独占的变量。
- unlock(解锁):作用于主内存的变量,把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定。
- read(读取):作用于主内存的变量,把一个变量从主内存传输到线程的工作内存中,以便随后的load动作使用。
- load(载入):作用于工作内存的变量,把read操作从主内存中得到的变量值放入工作内存的变量副本中。
- use(使用):作用于工作内存的变量,把工作内存中的一个变量的值传递给执行引擎。
- assign(赋值):作用于工作内存的变量,把一个从执行引擎接收到的值赋给工作内存的变量。
- store(存储):作用于工作内存的变量,把工作内存中一个变量的值传送到主内存中,以便后续的write操作使用。
- write(写入):作用于主内存的变量,把store操作从工作内存中得到的变量的值放入主内存的变量中。
文字挺多,其实刚好是一个整体过程,从主内存读取,传送到工作内存,然后工作内存这里接收,放到相应的位置,在将值传递给执行引擎,从执行引擎接收值到工作内存,然后把这个值从工作内存传送到主内存,最后放到主内存的相应位置。
Java内存模型的三大特性
1.原子性:由java内存模型来直接保证的原子性变量的操作包括:read、load、use、assign、store、write。可以认为基本数据类型的访问读写是具备原子性的。若需更大范围的原子性,需要synchronized关键字约束。
2.可见性:可见性是指当一个线程修改了共享变量的值,其他线程能够立即得知这个修改。。volatile、synchronized、final三个关键字可以实现可见性。
3.有序性:如果在本线程内观察,所有操作都是有序的;如果在线程中观察另外一个线程,所有的操作都是无序的。