jvm - 内存模型与线程

原创
2017/08/25 10:12
阅读数 11

JVM 通过定义内存模型来屏蔽各种硬件和操作系统的内存访问差异,以实现让java程序在各平台都能达到一致的内存访问效果。

工作内存可以类比为CPU中的高速缓存。

主内存与物理硬件的主内存类比。

内存间交互

8中操作都是原子的(除了long、doubley允许例外)。

  1. lock:作用于主存,标记线程独占。
  2. unlock:作用于主存,释放锁定的变量。
  3. read:作用于主存,将变量从主存读出,以便后续的load操作。
  4. load:作用于工作内存,将read读取的变量副本放入工作内存。
  5. use:作用于工作内存,将工作内存变量传给执行引擎。
  6. assign:将执行引擎的值赋给工作内存。
  7. store:作用于工作内存,从工作内存读出,传给主存,以便后续的write操作。
  8. write:作用于主存,将store的值保存到主存。

规定上述操作必须满足如下规定:

  1. 不允许read和load、store和write单独出现。
  2. 不允许丢弃assign操作,即变量在工作内存改变后必须将变化同步到主存。
  3. 不允许无原因地将数据从工作内存同步到主存(没有assign操作)。
  4. 变量智能在主存中产生。也就是说对变量实施use、store操作之前,必须先执行assign和load操作。
  5. 一个变量允许被同一个线程多次lock,但同时需要相同次数的unlock。
  6. 如果对一个变量进行lock操作,那么会清空工作内存此变量的值,执行引擎执行之前必须重新load或assign初始化值。
  7. 对变量进行unlock之前,必须有对应的lock。
  8. 对变量进行unlock之前,必须把变量同步回主存。

volatile

当一个变量定义为volatile后,具备两个特性,保证此变量对所有线程的可见性,这里的可见性指当一个线程改变了变量的值,新值对于其他程序是立即得知的。但并不是安全的,volatile变量也可以存在不一致的情况,但每次使用之前都要先刷新,执行引擎看不到不一致的情况,但是java的运算并不是原子操作(如++操作,对应多条字节码指令,每一条字节码指令有会对应多条机器指令)。

由于volatile只能保证可见性,所有不符合以下两条规则的场景下,仍然需要通过锁来保证。

  1. 运算结果不依赖变量的当前值,或者能确保只有一个线程修改变量的值。
  2. 变量不需要与其他的状态变量共同参与不变约束。

第二个特征是禁止指令重排序优化。

volatile变量在use之前必须有前置操作read和load操作。

assign之后必须立即有store和write操作。

volatile变量与普通变量的区别是:volatile保证新值能立即同步到主存,以及每次使用前立即从主存刷新。

先行发生

如果说操作A先行发生于B,就是说发生在操作B之前,操作A产生的影响能被操作B观察到。

一下是天然的先行发生关系,无需任何同步就已经存在:

程序次序:在一个线程内,书写在前面的操作先行发生于书写在后面的操作。

管程锁定:unlock操作先行发生于后面对同一锁的lock操作。

volatile:一个volatile的写操作先行发生于这个变量的读操作。

线程启动:Thread的start()先行发生此线程的每个动作。

线程中断:线程interrupt()方法的调用先行发生于被中断代码检测到中断事件的发生。

对象的终结:一个对象初始化完成(构造函数执行结束)先行发生于它的finalize()。

传递性:A先行发生B,B先行发生C,则A先行发生C。

 

 

 

 

 

 

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部