Java内存模型:
Java虚拟机规范中试图定义一种java内存模型(Java Memory Model,JMM)来屏蔽掉各类硬件和操做系统的内存访问差别,以实现让Java程序在各个平台下都能达到一致的内存访问效果。Jdk1.5(实现了JSR-133)发布后,java内存模型才成熟和完善起来。
1、主内存和工做内存:
java内存模型的主要目标是定义程序中的各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量这样的底层细节。
java内存模型规定了全部的变量都存储在主内存中(虚拟机内存的一部分)。每一个线程还有本身的工做内存,线程的工做内存中保存了 该线程使用到的变量的主内存的副本拷贝,线程对变量的全部操做都必须在工做内存中进行,而不能直接读写主内存中的变量。线程间的变量值的传递都须要经过主内存来完成。
线程、主内存、工做内存三者交互关系图以下: java
2、内存间交互操做:
Java内存模型定义了8种操做来完成主内存和工做内存之间的交互协议,即一个变量如何从主内存拷贝到工做内存、如何从工做内存同步回主内存的实现细节。虚拟机保证了下面的每一种操做的原子性、不可再分。
lock(锁定):做用于主内存的变量,它把一个变量标识为一条线程独占的状态。
unlock(解锁):做用于主内存变量,它把一个处于锁定状态的变量释放出来。
read(读):做用于主内存的变量,它把一个变量的值从主内存传输到线程的工做内存中,以便随后的load动做。
load(载入):做用于工做内存的变量,它把read操做的变量值放入工做内存的变量副本中。
use(使用):做用于工做内存的变量,它把工做内存的一个变量的值传递给执行引擎,
每当虚拟机遇到一个须要使用到变量的值的字节码指令的时候会执行这个操做。
assign(赋值):做用于工做内存的变量,它把一个从执行引擎接收到的值赋给工做内存的变量,
每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操做。
store(存储):做用于工做内存的变量,它把一个工做内存中的变量的值传送到主内存中,以便随后的write操做。
write(写入):做用于主内存的变量,它把store操做从工做内存中取到的变量的值放入到主内存的变量中。 安全
关系图: 并发
若是要把一个变量从主内存复制到工做内存,那就要顺序的执行read、load操做;
若是要把一个变量从工做内存同步到主内存,那就要顺序的执行store、write操做。
java内存模型只要求上述的两个操做必须按顺序执行,而没有保证必须是连续的执行。也就是说read和load之间、store和write之间是能够插入其余指令的。
同时java内存模型还规定了在执行上述的8中基本操做的时候必须知足以下规则: spa
2.1 不容许read和load、store和write操做之一单独出现,即不容许一个变量从主内存读取到了可是工做内存不接受,
或者从工做内存发起了回写可是主内存不接受的状况出现。
2.2 不容许一个线程丢弃它的最近的assign操做,即变量在工做内存中改变了以后必须把该变化同步到主内存。
2.3 不容许一个线程无缘由(没有发生过任何assign操做)的把数据从线程的工做内存同步到主内存中。
2.4 一个新的变量只能在主内存中诞生,不容许工做内存中直接使用一个未被初始化(load或assign)的变量,
也就是说对一个变量的user、store操做以前,必须限制性load和assign操做。
2.5 一个变量在同一时刻只容许一条线程对其进行lock操做,但lock操做能够被同一条线程重复执行屡次,
屡次执行lock后,要进行相同次数的unlock操做,变量才会被解锁。
2.6 若是对一个变量执行lock操做,那将会清空工做内存中此变量的值,在执行引擎使用这个变量前,
须要从新执行load或assign操做初始化变量的值。
2.7 若是一个变量事先没被lock操做锁定,那就不容许对他执行unlock操做,也不容许unlock一个呗其余线程锁定住的变量。
2.8 对一个变量执行unlock操做以前,必须先把此变量同步到主内存中(执行store、write操做)。
这8种内存访问操做以及上述的限定,再加上volatile(后续介绍)的一些特殊限定,就已经彻底肯定了java程序中哪些内存访问操做在并发下是安全的。 操作系统
参考:深刻理解Java虚拟机(周志明 著) 线程