博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
volatile
阅读量:7181 次
发布时间:2019-06-29

本文共 1270 字,大约阅读时间需要 4 分钟。

此文已由作者赵计刚授权网易云社区发布。

欢迎访问,了解更多网易技术产品运营经验。

注:在阅读本章之前,先要了解Java内存模型,见上一章《》,链接如下:

1、volatile用法

具体的用法可以参照《》中的Segment内部类的count属性,可以看看多线程情况下怎样对其进行操作的,具体链接如下;

或者可以参照《》中的底层数组,具体链接如下;

 

2、具体的实现原理

  • 对volatile变量执行写操作时,会在写操作后加入一条store屏障指令

  • 对volatile变量执行读操作时,会在读操作前加入一条load屏障指令

说人话:

  • 对volatile变量执行读操作时,都要强制的先从主内存读取最新的变量值到工作内存,然后再读工作内存中所存储的变量副本

  • 对volatile变量执行写操作时,又会强制的将工作内存中的刚刚改变的值写到主内存中去

通过上边这样模式,每个线程拿到的volatile变量值都是最新的。

注意:

volatile无法实现原子性:

eg.

private volatile int count = 0;

假设现在有两条线程分别对count执行加1操作,那么期待的结果最后count==2,但是看下边的分析:

假设有如下流程:

1)线程a获取了count==0;

2)线程b获取了count==0;

3)线程b对count+1,之后写入主内存count==1;

4)线程a对count+1,之后写入主内存count==1;

结果count==1而非count==2,原因就是线程a获取count后,volatile不能实现原子性,这个时候b也能去操作count。

想要实现原子性,使用synchronized去锁住增加方法,或者使用ReentrantLock去锁住增加代码;当然,以上场景使用AtomicInteger更好。

 

3、volatile使用场景

  • 运算结果并不依赖当前值,例如Boolean就可,而number++这样的就不行,这样的情况使用锁

  • 运算结果依赖当前值但是能够确保只有单一线程修改变量的值,例如中Segment的count变量

    • count变量只能由单一线程来改变(因为put和remove都是加锁的),但是修改后未必能及时刷新到主内存;这时候读线程去读取的话就可能读到旧数据。所以需要volatile来保证可见性。

  • 变量不需要与其他的状态变量共同参与不变约束,例如low<up这样的场景就不行

  • 在访问变量时需要使用锁,就不要使用volatile(《java并发编程实战》)

所以说,volatile只能实现部分线程安全(实际上只能实现可见性)。 如果volatile用得好的话,比synchronized强不少,因为不需要上下文切换。

注:

  • 关于volatile禁止指令重排序的介绍去看《深入理解Java虚拟机(第二版)》第十二章"Java内存模型与线程"

  • 通常情况下,能用volatile解决的就不去用synchronized了

更多网易技术、产品、运营经验分享请。

相关文章:

【推荐】 
【推荐】 
【推荐】 

转载地址:http://abszm.baihongyu.com/

你可能感兴趣的文章
基类中定义的虚函数,子类中必须要覆盖吗?为什么?
查看>>
SingleNumber
查看>>
linux 硬盘分区与挂载
查看>>
GStreamer 1x play mp4 file
查看>>
后缀数组模板
查看>>
我的友情链接
查看>>
走向DBA[MSSQL篇] 面试官最喜欢的问题 ----索引+C#面试题客串
查看>>
在7层分发中,http,mysql是如何控制数据包的走向的
查看>>
RHEL5下部署LAMP+SVN+SSL
查看>>
LINUX REDHAT第九单元练习题
查看>>
我的友情链接
查看>>
一时所想
查看>>
Linux cat 学习之路(1)
查看>>
cobbler自动化部署多种类型的操作系统,一个软件全部搞定
查看>>
tdpsql 相关笔记
查看>>
我的友情链接
查看>>
顺序队列和链式队列的实现
查看>>
python 关键字 之 and 与 or
查看>>
信管师培训之第二节课作业(系统集成知识)
查看>>
ARP欺骗
查看>>