[098]技术-java volatile关键字原理解析

2017-12-24  本文已影响0人  shawnxjf

volatile可见性

我们知道volatile关键字可以保证线程之间可见。什么叫可见性?即一个线程A修改的数据值为d1能够立马被线程B可见(当线程B去读取的时候)。
那么我们想一下如何设计线程可见性呢?最简单最直觉的设计就是thread1,thread2 同时操作主内存变量 var1。
其对应的模型图为:


image.png

但实际上jvm中,线程是不可以直接访问主内存的,jvm会为每一个线程生成一个对应的工作内存,工作内存的变量是主内存变量的拷贝。不管是基本类型还是复合数据类型,其变量都会在工作内存存在一份副本。然后jvm定义了一套工作内存和主内存变量同步的规范。
对于volatile变量来说 assign后必定要store,load前一定要先read。其对应的逻辑如下图所示:

image.png

备注:关于assign,store,load,read简单定义如下(如需要了解详细内容请参考《深入java虚拟机》):

assign:作用于工作内存变量,即执行引擎把运算结果付给工作内存变量
store:把工作内存 -> 主内存
read:把主内存-> 工作内存
load:工作内存 -> 执行引擎
lock:  如果对一个变量执行lock操作,那么将会清空工作内存中此变量的值(包括其他cpu对应的工作内存),在执行引擎使用前必须重新执行load和assign操作。lock操作被同一线程执行多次lock后,执行同样次数的unlock操作变量才会被解锁(可重入锁的底层机制)```
从jvm 的内存模型划分我们知道,每个线程都有其工作副本,线程与线程之间变量通过主内存沟通。而从工作内存与主内存交互模式我们知道。如果一个变量修饰为volatile,则在assign副本值后会立马回写到主内存,读取一个变量的值时必定先从主内存读取刷新该值。这样就保证了线程变量的可见性。

注意:这里的工作内存与主内存是jvm内存另一维度的划分(与堆栈划分是不同的),它是一种逻辑层次的划分。从硬件角度来看,主内存主要存放于硬件内存而为了获得更好的性能工作内存可能存储于高速缓存或寄存器中。

## 关于volatile的使用
volatile 关键字保证了  写入一个变量和读取一个变量之间的顺序,即读取的一个变量必定是最近写入的值。
但是它没有保证两个写入之间的协同。对于只有一个线程写入或者变量只会被写入一次时,使用volatile是线程安全的。

volatile shutdownflag = false;
public void shutdown
{
shutdown =true;
}
public void dowork(){
if (shutdownflag)
{
// do stuff
}
}


## 写在后面的话
以前从书中看到volatile 知识,是随着书中的讲解代入进去的。一下子深入到原理,比如lock锁机制、内存屏障。但是先了解volatile运行的模式即是什么?然后自己去想想如何实现,比如如何实现可见性(自己很容易推导:assign后立马更新到内存),画出执行引擎-工作内存-主内存图,自己也从中提出更多的问题,比如多个cpu是如何处理的等等。
另外这里提出一个问题:synchronized如何实现同步的,lock对象是如何通过volatile和cas实现锁的机制的。




上一篇 下一篇

猜你喜欢

热点阅读