您的位置:首页 > 编程语言 > Java开发

jvm - 内存模型与线程

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

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

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

内存间交互

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

lock:作用于主存,标记线程独占。

unlock:作用于主存,释放锁定的变量。

read:作用于主存,将变量从主存读出,以便后续的load操作。

load:作用于工作内存,将read读取的变量副本放入工作内存。

use:作用于工作内存,将工作内存变量传给执行引擎。

assign:将执行引擎的值赋给工作内存。

store:作用于工作内存,从工作内存读出,传给主存,以便后续的write操作。

write:作用于主存,将store的值保存到主存。

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

不允许read和load、store和write单独出现。

不允许丢弃assign操作,即变量在工作内存改变后必须将变化同步到主存。

不允许无原因地将数据从工作内存同步到主存(没有assign操作)。

变量智能在主存中产生。也就是说对变量实施use、store操作之前,必须先执行assign和load操作。

一个变量允许被同一个线程多次lock,但同时需要相同次数的unlock。

如果对一个变量进行lock操作,那么会清空工作内存此变量的值,执行引擎执行之前必须重新load或assign初始化值。

对变量进行unlock之前,必须有对应的lock。

对变量进行unlock之前,必须把变量同步回主存。

volatile

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

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

运算结果不依赖变量的当前值,或者能确保只有一个线程修改变量的值。

变量不需要与其他的状态变量共同参与不变约束。

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

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。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 线程