Java内存模型

167 阅读4分钟

Java内存模型

Java内存模型规定了所有的变量都存储在主内存中。每条线程还有自己的工作内存,线程的工作内存中保存了被该线程使用的变量的主内存副本,线程对变量的所有操作(读取,赋值等)都必须在工作内存中进行,而不能直接读写主内存中的数据。不同的线程之间也无法直接访问对方工作内存中的变量,线程间变量值的传递均需要通过主内存来完成。

内存间交互操作

关于主内存与工作内存之间的交互协议,即一个变量如何从主内存拷贝到工作内存,如何从工作内存同步回主内存这一类的实现细节。Java内存模型中定义了以下8种操作来完成。

lock:作用于主内存的变量,它把一个变量标识为一条线程独占的状态

unlock:作用于主内存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定

read:作用于主内存的变量,它把一个变量的值从主内存传输到线程的工作内存中。以便随后的load动作使用

write:作用于主内存的变量,它把store操作从工作内存中得到的变量的值放入主内存的变量中

对于volatile型变量的特殊规则

当一个变量被定义成volatile之后,它将具备两项特性:

第一项是保证此变量对所有的线程的可见性。这里的“可见性”是指当一条线程修改了这个变量的值,新值对于其他线程来说是可以立即得知的。而普通变量并不能做到这一点,普通变量的值在线程间传递时均需要通过主内存来完成。

使用volatile变量的第一个语义是禁止指令重排序优化,普通的变量仅会在保证在该方法的执行过程中所有依赖赋值结果的地方都能获取到正确的结果,而不能保证变量赋值操作的顺序与程序代码中的执行顺序一致。(禁止指令重排,原理是在字节码中加了lock内存屏障,指令重排时不能把后面的指令重排序到内存屏障之前的位置。)

原子性、可见性、有序性

1.原子性

由Java内存模型来直接保证的原子性变量操作包括read、load、assign、use、store和write

2.可见性

可见性就是指当一个线程修改了共享变量的值时,其他线程能够立即得知这个修改。Java内存模型是通过在变量修改后将新值同步回主内存,在变量读取前从主内存刷新变量值这种依赖主内存作为传递媒介的方式来实现可见性的。无论是普通变量还是volatile变量都是如此。普通变量与volatile变量的区别是,volatile的特殊规则保证了新值能立即同步到主内存,以及每次使用前立即从主内存刷新。因此我们可以说volatile保证了多线程操作时变量的可见性,而普通变量则不能保证这一点。

3.有序性

Java语言提供了volatile和synchronize两个关键字来保证线程之间操作的有序性。volatile关键字本身就包含了禁止指令重排序的语义

synchronized关键字能够保证:原子性,可见性,有序性。

volatile可以保证可见性,有序性,但是不能保证原子性

先行发生原则

先行发生时Java内存模型中定义的两项操作之间的偏序关系,比如说操作A先行发生于操作B,其实就是说在发生操作B之前,操作A产生的影响能被操作B观察到,“影响”包括修改了内存中共享变量的值、发送了消息、调用了方法等

Ref:

《深入理解JVM虚拟机》第三版——周志明