对volatile关键字的理解

 

说volatile关键字之前先简单说一下JAVA内存模型。
就像CPU为提高运算速度有自己的高速缓存一样,JAVA每个线程都有自己的工作内存,然而成员变量只能在主内存中进行创建、销毁,主内存就是设备硬件内存,只有一个,所有线程共享。
每个线程都需要从主内存中将本线程需要的变量拷贝一个副本到工作内存中,每个线程直接操作的为工作内存中的变量副本,这就可能导致线程不安全。
JVM规定线程工作内存跟主内存之间对变量的操作通过lock、unlock、read、load、use、assign、store、write等8个指令来完成。
lock、unlock:跟锁有关的两个指令,跟本文无关。
read:从主内存中读取某个变量到工作内存
load:将read到的变量加载到工作内存的变量副本中
use:线程去使用副本中的变量
assign:逻辑区对变量赋值操作,给变量副本赋值
store:将赋值后的变量存到主内存
write:将从工作内存store过来的变量更新到主内存中
ps:read、load跟store、write必须成对出现

先说一下volatile关键字的意思,线程在使用volatile修饰的变量之前,会从主内存中获取该变量的值;再对改变量做更改后会立即写入主内存中。
其实可以分为两段解释
在执行use指令之前,前一个指令必须是load指令;在执行load指令之前,前一个指令必须是read。use、load、read三个指令是一个原子操作,中间不允许插入任何指令。
同样,赋值操作时,assign指令的下一个指令必须是store,store指令的下一个指令必须是write,assign、store、write这三个指令是一个整体,不可中断。
这样就可以解释使用该变量的时候该变量是从主存中读取的最新的值,更改后立即同步到主存中,实现了volatile修饰的变量在线程间的可见性。

实现线程间可见性并不等于是线程安全的,虽然有人将volatile称作轻量级锁。针对非原子操作可能出现线程不安全的问题,非原子操作代表运算过程中可中断。以i++操作举个例子。
假设当前i=1
线程1执行i++操作的时候,use、load、read获取到i的值为1,然后时间片很凑巧的多次分给了线程2,
线程2执行i++操作,此时通过use、load、read获取到i的值仍为1,经过运算后assign、store、write到主存中。主存中此时i的值为2。
此时时间片分给线程1,线程1接着刚才的操作,此时线程1已经执行过use指令了,所以直接进行运算,运算后1的值为2,然后assign、store、write到主存中。主存中此时i的值为2。
所以对于此类操作使用原子类或者加锁。

使用volatile关键字修饰的变量大多用在只有一个线程会去修改这个变量,但有多个线程依赖该变量做运算或做判断。
还有一点就是volatile可以一定程度上保证代码的有序性,可以起到分隔代码的作用。
说起分隔代码,那就需要说一下有序性的问题了,关于有序性这块我了解的也不多,先说一下我自己的理解,希望有了解的大佬帮忙瞅一眼,给个清楚的解释ORZ
有序性的源头是CPU执行指令的的时候,为了保证CPU性能利用率达到最大,遇到阻塞或其他IO等类型操作的时候,会挂起去执行其他指令。
JVM支持代码执行顺序的重排序。JAVA代码执行的时候并不是逐行顺序执行下来的,能保证执行顺序的只有有依赖关系的代码,比如 int a,b; a = 1; b = a*2+1; 但重排序并不影响执行结果,所以锁可以某种程度保证有序性。
对于没有依赖关系的代码执行顺序并不能保证,在多线程的情况下,如果某个线程需要依赖另一线程中某些资源及变量就可能会出现问题。我在网上看到其他人举的一个示例:
线程1:
context = loadContexy();  //初始化context  --  1
inited = true; //初始化标志 -- 2
线程2:
while(!inited){
    sleep();
}
doSomething(context);
语句1跟语句2没有依赖关系,那么可能语句2执行顺序会在语句1之前,假设发生重排序,语句2先执行后,线程2会判定已经初始化完成,然后去用context执行某些操作。

回到本话题中,volatile可以一定程度上保证代码的有序性。
volatile相当于一个屏障,在volatile修饰的变量前面的那部分代码始终在其前面执行,在volatile修饰变量后面的代码始终在其后面执行。volatile可以将其分隔开。
上面那个例子如果改为volatile boolean inited = true;那么就可以保证在其前面的context = loadContexy();肯定会在代码2前面执行。

 

 

学JAVA时间尚短,前辈建议多发博客,多与大佬们交流。希望大佬们看到有理解不对、遗漏或者需要补充的地方帮忙指点一下,感激不尽^_^

 

你可能感兴趣的:(JAVA)