Java内存模型
2.Java内存模型
由于Java虚拟机试图定义一种Java内存模型来屏蔽掉各种硬件和操作系统的内存访问中的差异,所以制作这样一个统一的内存模型。
2.1主内存于工作内存
Java内存模型规定了所有的变量都存储在主内存中。每条线程都保有自己的工作线程,线程的工作内存中保存了该线程所用到的变量的副本拷贝,线程对变量的操作都必须在工作内存中进行,而不能直接写入主内存。不同线程之间也无法范围其他线程的工作内存。(注意这里所讲的于Java虚拟机中的结构不是同一个概念,如果要等效的话,可以看桌主内存主要是Java堆中的实例对象数据部分,而工作内存的话可以看成Java虚拟机丈中的部分区域)
2.2内存见得相互操作
关于主内存和工作内存之间的具体现已,如何从主内存中拷贝到工作内存中。Java内存模型中定义了8中操作来完成这一过程,虚拟机必须保证下面提到的每一个操作符合原子类型(除了double,long)。
1、luck(锁定):作用于主内存的变量,它把一个变量标示为一条线程独占的状态。
2、unlock(解锁):作用于主内存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定。
3、read(读取):作用于主内存的变量,它把一个变量的值从主内存传输到工作内存中,以便随后的load动作使用。
4、load(载入):作用于工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中。
5、use(使用):作用于工作内存的变量,它把工作内存中的一个变量的值传递给执行引擎,每当虚拟机遇到一个需要使用到变量的值得字节码指令时将会执行这个操作。
6、assign(赋值):作用于工作内存的变量,它把一个从执行引擎接收到的值赋给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作。
7、store(存储):作用于工作内存的变量,它把工作内存中的一个变量的值传递到主内存中,以便随后的write操作使用。
8、write(写入):作用于主内存的变量,它把store操作从工作内存中得到的变量值放入主内存的变量中。
Java内存模型还规定了执行上述8种基本操作时必须满足如下规则:
1、不允许read和load、store和write操作之一单独出现,以上两个操作必须按顺序执行,但没有保证必须连续执行,也就是说,read与load之间、store与write之间是可插入其他指令的。
2、不允许一个线程丢弃它的最近的assign操作,即变量在工作内存中改变了之后必须把该变化同步回主内存。
3、不允许一个线程无原因地(没有发生过任何assign操作)把数据从线程的工作内存同步回主内存中。
4、一个新的变量只能从主内存中“诞生”,不允许在工作内存中直接使用一个未被初始化(load或assign)的变量,换句话说就是对一个变量实施use和store操作之前,必须先执行过了assign和load操作。
5、一个变量在同一个时刻只允许一条线程对其执行lock操作,但lock操作可以被同一个条线程重复执行多次,多次执行lock后,只有执行相同次数的unlock操作,变量才会被解锁。
6、如果对一个变量执行lock操作,将会清空工作内存中此变量的值,在执行引擎使用这个变量前,需要重新执行load或assign操作初始化变量的值。
7、如果一个变量实现没有被lock操作锁定,则不允许对它执行unlock操作,也不允许去unlock一个被其他线程锁定的变量。
8、对一个变量执行unlock操作之前,必须先把此变量同步回主内存(执行store和write操作)。
2.3volatile变量访问的特殊规则
关键字volatile可以说是Java提供的轻量机的线程同步机制(这里有人说同步锁我并不赞成),Java内存模型对volatile做了一些特殊的范文规则,一个变量被定义为volatile后具备两种特征,一个是保证此线程可以被其他线程看到,及一条线程修改了这个变量的值,可以立马被其他线程看到,而普通线程只能够等到运行结束后通过主内存知道。
由于volatile的变量只能保证可见性,所以遇到同步问题仍需要加锁。
使用volatile还可以保证禁止指令重排序。指令重排是指CPU采用了允许将多条指令不按照程序顺序进行处理,指令重排在一些四则运算中,有一些作用,可以提高CPU的运行效率。
2.4.对于long和double型变量的特殊规则
Java内存模型中lock,unlock,read,load,assign,use,stor,write这八个操作具有原子型,但是对于64位的long和double而言需要两个内存空间来存储,及允许实现load,store,read,write等四个原子操作。如果有多个线程共享一个并未什么味volatile的long或double类型的变量,并且同事对他们进行读写和修改操作,那么可能会读取到一个非原。
2.5 原子性,可见性与有序性
2.6先行发生原则
程序次序规则:在一个线程中,按照程序代码顺序,书写在前面的代码操作先行发生于后面的操作
管程锁定规:一个 unlock 操作先行发生于后面对同一个锁的 lock 操作。“后面”指的是时间的先后顺序。
volatile 变量规则:对一个 volatile 变量的写操作先行发生于后面对这个变量的读操作。“后面”指的是时间的先后顺序。
线程启动规则:Thread 对象的 start() 方法先行发生于此线程的每一个动作。
线程终止规则:线程中所有操作先行发生于对此线程的终止检测。
线程中断规则:对线程 interrupt() 方法的调用先行发生于代码检测到中断事件的发生。
对象终结规则:一个对象的初始化完成(构造函数结束)先行发生于它的 finalize() 方法的开始。
传递性:如果操作A先行发生于操作B,操作B先行发生于操作C,那么操作A先行发生于操作C。
时间的先后与先行发生原则并没有太多关系
原文地址:https://my.oschina.net/puzhiyuan/blog/852217