JVM学习(六):Java内存模型
1、Java内存模型(Java Memory Model,JMM):线程、主内存和工作内存。所有的变量都存储在主内存(虚拟机内存的一部分)中,每条线程还有自己的工作内存。线程对变量的所有操作(读取、赋值等)必须在工作内存中进行,不同线程之间无法直接访问对方工作内存中的变量,需要通过主内存来完成。
2、如果要把一个变量从主内存复制到工作内存,就要顺序地执行read和load操作,如果要把变量从工作内存同步回主内存,就要顺序地执行store和write操作。
3、由于volatile变量只能保证可见性,不能保证原子性,为了保证线程并发的安全性,使用volatile时必须满足以下运算场景:
(1)运算结果并不依赖变量的当前值,或者能够确保只有单一的线程修改变量的值。
(2)变量不需要与其他的状态变量共同参与不变约束。
4、Java内存模型是围绕着在并发过程中如何处理原子性、可见性和有序性来建立的:
(1)原子性(Atomicity):基本数据类型的访问读写是具备原子性的(64位的long和double除外),如果需要更大范围的原子性保证,需要lock和unlock来操作,对应字节码指令monitorenter和monitorexit,对应Java代码中就是sychronized关键字。
(2)可见性(Visibility):当一个线程修改了共享变量的值,其他线程能够立即得知这个修改。可以通过volatile、sychronized和final实现。
(3)有序性(Ordering):如果在本线程内观察,所有的操作都是有序的(线程内表现为串行的语义As-If-Serial),如果在一个线程中观察另一个线程,所有的操作都是无序的(指令重排序和工作内存与主内存同步延迟)。可以通过volatile和synchronized实现。
5、Java的先行发生(happens-before)原则:
(1)如果说操作A先行发生于操作B,A产生的影响能被操作B观察到。
(2)Java内存模型中存在的天然先行发生关系:程序次序规则(一个线程内按程序控制流顺序)、管程锁定规则(unlock先行发生于后面对同一个锁的lock)、volatile变量规则(写操作先行发生于后面的读操作)、线程启动规则、线程终止规则、线程中断规则、对象终结规则(初始化先行发生于finalize()方法)、传递性(A先行发生于B,B先行发生于C,则A先行发生于C)。
(3)一个操作的时间先后顺序与先行发生原则之间基本没有太大的关系,对于读写共享变量的并发操作,应该以先行发生原则来判断线程是否安全。