Java内存模型、先行发生原则

 2019-12-10 16:15  阅读(995)
文章分类:Java Core
  • 由于计算机的存储设备和处理器的运算速度有几个数量级的差距,所以计算机系统不得不加入一层读写速度尽可能接近处理器运算速度的高速缓存来作为内存与处理器之间的缓冲。但这引入了新问题:缓存一致性
  • 为了使得处理器内部的运算单元能尽量被充分利用,处理器可能会对输入代码进行乱序执行优化,类似的java虚拟机的即时编译器中也有类似的指令重排序优化。

java内存模型

java内存模型可屏蔽掉各种硬件和操作系统的内存访问差异,实现了java程序在各种平台下都能达到一致的内存访问效果。
主要目标:定义程序中各个变量的的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量的底层细节。
java内存模型规定了所有的变量都存储在主内存中,每条线程还有自己的工作内存,线程的工作内存中保存了被该线程使用到的变量的主内存副本拷贝,线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存中的变量。不同的线程之间也无法直接访问对方的工作内存中的变量,线程间变量值的传递都需要通过主内存来完成。
线程、主内存、工作内存三者的关系如下图:
20191210001689\_1.png

主内存与工作内存之间的交互操作

java内存模型定义了8中操作来完成其交互,并且每一种操作都是原子的、不可再分的。
1)lock锁定,作用于主内存的变量,将变量标示为线程独占状态。
2)unlock解锁,作用于主内存的变量,释放处于锁定状态的变量。

  • 对一个变量执行unlock操作之前必须先把此变量同步回主内存中
  • 不允许unlock一个被其它线程锁定住的变量。

3)read读取,作用于主内存的变量,将变量从主内存传输到线程的工作内存中,以便后面的load动作使用。
4)load载入,作用于工作内存的变量,把read操作从主内存得到的变量值放入工作内存的变量副本中。

  • 把变量从主内存复制到工作内存,要顺序的执行read、load操作,并且这两个操作不能单独出现,即不允许一个变量从主内存读取了但工作内存不接受。

5)use使用,作用于工作内存的变量,将工作内存中的变量值传递给执行引擎。
6)assign赋值,作用于工作内存的变量,把从执行引擎接收到的值赋给工作内存的变量。

  • 不允许线程丢弃此操作,即变量在工作内存中改变了之后必须把该变化同步回主内存。
  • 没有发生过此操作则不允许把数据从线程的工作内存同步回主内存中。

7)store存储,作用于工作内存的变量,把工作内存中的变量传送到主内存中,以便后面的write操作使用。
8)write写入,作用于主内存的变量,把store操作从工作内存中得到的变量值放入主内存的变量中。

  • 把变量从工作内存同步到主内存,要顺序的执行store、write操作,并且这两个操作不能单独出现,即不允许工作内存发起回写了但主内存不接受。

以上8种操作和其规定虽然严谨但是繁琐麻烦,所以这种定义的一个等效判断原则——先行发生原则,来确定一个访问在并发环境下是否安全。

先行发生原则

1)程序次序规则,在一个线程中,按照程序代码顺序,书写在前面的操作先行发行于书写在后面的操作。
2)管程锁定规则,一个unlock操作先行发生于后面对同一个锁的lock操作。
3)volatile变量规则,对一个volatile变量的写操作先行发生于后面对这个变量的读操作。
4)线程启动规则,Thread对象的start()方法先行发生于此线程的每一个动作。
5)线程终止规则,线程中的所有操作都先行发生于对此线程的终止检测。
6)线程中断规则,对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生。
7)对象终结规则,一个对象的初始化完成先行发生于他的finalize()方法的开始。
8)传递性,如果操作A先行发生于操作B,操作B先行发生于操作C,那么操作A先行发生于操作C。

一个操作时间上的先发生和先行发生没有任何推导关系。

点赞(0)
版权归原创作者所有,任何形式转载请联系作者; Java 技术驿站 >> Java内存模型、先行发生原则

相关推荐