注意,本文所讲的内存模型与Java内存区域中的Java堆、栈、方法区等并不是同一个层次的内存划分,这两者基本上是没有关系的,如果两者一定要勉强对应起来,那从变量、主内存、工作内存的定义来看,主内存主要对应于Java堆中的对象实例数据部分[插图],而工作内存则对应于虚拟机栈中的部分区域。
JAVA虚拟机规范中试图定义一种内存模型来屏蔽不同操作系统中的内存访问差异,以实现一致的内存访问效果。先上图,本文所讲内容基于下图展开,线程,工作内存,和主内存的交互关系。工作内存为线程私有内存,主内存为线程共享内存。
线程的工作内存和主内存的交互
Java内存模型定义了8中操作来实现变量从主内存拷贝到工作内存,以及从工作内存同步到主内存,Java虚拟机必须保证这些操作的原子性。
- lock (锁定):作用于主内存,将主内存中的变量变为锁定状态,锁定状态下的变量不能被其他线程锁定。
- unlock (解锁):作用于主内存,将主内存中的变量变为解锁状态,解锁后的变量可以被其他线程锁定。
- read (读取):作用于主内存,将主内存中的变量值传输到线程的工作内存。
- load (载入):作用于工作内存,将read读取的变量值赋值给工作内存的变量副本。
- use (使用):作用于工作内存,当虚拟机遇到一条需要使用变量值的字节码指令时,将该变量的值传递给执行引擎。
- assign (赋值):作用于工作内存,当虚拟机遇到一条给变量赋值的字节码指令时,把从执行引擎获取到的值赋值给变量
- store (存储):作用于工作内存,将变量值传送到主内存中。
- write (写入):作用于主内存,将store传输过来的值赋值给主内存中的变量。
变量值从主内存到线程的工作内存,必须顺序的执行read 和 load ,把变量值从线程的工作内存同步到主内存,必须顺序的执行store 和 write,除此之外,在执行上述8个操作时还必须满足以下条件,以及对volatile关键字的一些特殊规则,才能保证在并发条件下的内存访问操作是安全的。
- 不允许read和load、store和write操作之一单独出现,即不允许一个变量从主内存读取了但工作内存不接受,或者从工作内存发起回写了但主内存不接受的情况出现。
- 不允许一个线程丢弃它的最近的assign操作,即变量在工作内存中改变了之后必须把该变化同步回主内存。
- 不允许一个线程无原因地(没有发生过任何assign操作)把数据从线程的工作内存同步回主内存中。
- 一个新的变量只能在主内存中“诞生”,不允许在工作内存中直接使用一个未被初始化(load或assign)的变量,换句话说,就是对一个变量实施use、store操作之前,必须先执行过了assign和load操作。
- 如果对一个变量执行lock操作,那将会清空工作内存中此变量的值,在执行引擎使用这个变量前,需要重新执行load或assign操作初始化变量的值。
- 如果一个变量事先没有被lock操作锁定,那就不允许对它执行unlock操作,也不允许去unlock一个被其他线程锁定住的变量。
- 对一个变量执行unlock操作之前,必须先把此变量同步回主内存中(执行store、write操作)。