volatile关键字解析

在给 volatile关键字解析 之前 希望看本文的朋友对Java内存模型有一定的了解;不了解的朋友可以先看看Java内存模型

一、volatile关键字有什么用呢?

1、保证了不同线程访问同一个变量时的可见性,也就是说A线程修改了一个变量的值,B线程C线程能马上就能看到这个变量的最新值。

2、禁止指令的重排序。

1、volatile关键字能保证可见性吗?

看一个简单的例子:

//线程1
int i = 1;
i = 100;

//线程2
int k = i ;

如果了解Java内存模型,相信你一定可以一眼看出,在多线程的情况下,线程1的是CPU1,执行线程2的是CPU2。由上面的分析可知,当线程1执行 i =100这句时,会先把i的初始值加载到CPU1的高速缓存中,然后赋值为100,那么在CPU1的高速缓存当中i的值变为100了,却没有立即写入到主存当中。此时线程2执行 k = i,它会先去主存读取i的值并加载到CPU2的缓存当中,注意此时内存当中i的值还是0,那么就会使得 k 的值为0,而不是100,如果加了volatile 呢?

加上了volatile,就相当于给访问 volatile 修饰变量的线程 一双火眼金睛~

线程1会把volatile修饰的这个变量的每一个操作后的值都告诉主存,其他线程任何时候都可以读取到最新最正确的值;

2、volatile关键字能保证有序性吗?

看一个简单的例子:

//线程1  
resourse =  config.load(); //语句1:假设是加载一个文件完成初始化;  
boolean flag = true;//语句2   
  
//线程2  
if(flag=false){  
    Thread.sleep(1000);  
}  
add(resourse);

Java内存模型中我们举过这个例子,在多线程的情况下:如果语句2先执行了,可能导致发生异常;如果给flag变量加上volatile 关键字,volatile关键字能保证在它之前的语句1执行了,才会执行它自己语句2; 再看一个单线程的例子:

a = 1;//语句1
b = 2;//语句2
volatile boolean flag = true;//语句3
a = 4;//语句4
b = 5;//语句5

我们知道由于flag变量为volatile变量,那么在进行指令重排序的过程的时候,不会将语句3放到语句1、语句2前面,也不会讲语句3放到语句4、语句5后面。但是要注意语句1和语句2的顺序、语句4和语句5的顺序是不作任何保证的。

并且volatile关键字能保证,执行到语句3时,语句1和语句2必定是执行完毕了的,且语句1和语句2的执行结果对语句3、语句4、语句5是可见的。

3、volatile关键字能保证原子性吗?

volatile并不能保证一个操作是原子操作,为了让一个操作是原子操作可以使用synchronized关键字和Lock锁来实现;

二、volatile 使用场景

在多线程的情况下,需要进行读(获取)操作时可以使用volatile 关键字来修饰变量,在进行写操作时,还是需要使用synchronized关键字和Lock锁来实现。

举个简单的例子:concurrenthashmap 的 put 操作是要加锁才能保证把节点放进“桶”的时候是线程安全的,

而 get 操作是不需要加锁的,原因就是 节点 的属性 使用了volatile 关键字;

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券