volatile关键字解析

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

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

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

2、禁止指令的重排序。

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

看一个简单的例子:

[java] view plain copy

  1. <span style="font-size:18px;">//线程1
  2. int i = 1;  
  3. i = 100;  
  4. //线程2
  5. int k = i ;</span>  

如果了解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关键字能保证有序性吗?

看一个简单的例子:

[java] view plain copy

  1. <span style="font-size:18px;">//线程1  
  2. resourse =  config.load(); //语句1:假设是加载一个文件完成初始化;  
  3. boolean flag = true;//语句2   
  4. //线程2  
  5. if(flag=false){    
  6.     Thread.sleep(1000);    
  7. }    
  8. add(<span style="font-family:Verdana, Arial, Helvetica, sans-serif;">resourse</span>);</span>  

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

再看一个单线程的例子:

[java] view plain copy

  1. <span style="font-size:18px;">a = 1;//语句1
  2. b = 2;//语句2
  3. volatile boolean flag = true;//语句3
  4. a = 4;//语句4
  5. b = 5;//语句5</span>

我们知道由于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 关键字;

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏数据结构与算法

3185 队列练习 1

3185 队列练习 1 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description 给定一...

3026
来自专栏别先生

python的学习和使用

1330
来自专栏木子昭的博客

简单点! python匿名函数!

适用场景 懒得为函数起名 函数只用一次 好处 写起来方便 避免对函数命名空间的污染 用法 按照字典特定键排序 ? 对字典年龄进行排序 格式 lambda 参数 ...

28010
来自专栏mukekeheart的iOS之旅

Java基础——异常体系

在Java中,异常对象都是派生于Throwable类的一个实例,Java的异常体系如下图所示: ?    所有的异常都是由Throwable继承而来,在下一层立...

2797
来自专栏ppjun专栏

kotlin internal 关键字使用

internal 修饰类的方法,表示这个类方法只适合当前module使用,如果其他module使用的话,会找不到这个internal方法或者报错。下面我们在mo...

1.5K2
来自专栏linux运维学习

linux学习第六十四篇:Shell脚本中的逻辑判断,文件目录属性判断, if特殊用法,case判断

Shell脚本中的逻辑判断 格式1:if 条件 ; then 语句; fi 格式2:if 条件; then 语句; else 语句; fi 格式3:if …; ...

3176
来自专栏技术小站

编程填空:第i位替换 编程填空:第i位取反 编程填空:左边i位取反

写出函数中缺失的部分,使得函数返回值为一个整数,该整数的第i位和m的第i位相同,其他位和n相同。

2031
来自专栏个人随笔

房上的猫:switch选择结构,与选择结构总结

switch选择结构: ? 一.定义:  switch选择结构,可以方便地解决等值判断问题 二.语法:  switch(表达式){   case 常量1:   ...

34811
来自专栏linux系统运维

正则介绍以及grep

1223
来自专栏向治洪

java造成内存泄露原因

一、Java内存回收机制  不论哪种语言的内存分配方式,都需要返回所分配内存的真实地址,也就是返回一个指针到内存块的首地址。Java中对象是采用new或者反射的...

24910

扫码关注云+社区

领取腾讯云代金券