附2 volatile
注:在阅读本章之前,先要了解Java内存模型,见上一章《附1 Java内存模型与共享变量可见性》,链接如下:
http://www.cnblogs.com/java-zhao/p/5124725.html
1、volatile用法
具体的用法可以参照《第二章 ConcurrentHashMap源码解析》中的Segment内部类的count属性,可以看看多线程情况下怎样对其进行操作的,具体链接如下;
http://www.cnblogs.com/java-zhao/p/5113317.html
或者可以参照《第三章 CopyOnWriteArrayList源码解析》中CopyOnWriteArrayList的底层数组,具体链接如下;
http://www.cnblogs.com/java-zhao/p/5121944.html
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++这样的就不行,这样的情况使用锁
- 运算结果依赖当前值但是能够确保只有单一线程修改变量的值,例如ConcurrentHashMap中Segment的count变量
- count变量只能由单一线程来改变(因为put和remove都是加锁的),但是修改后未必能及时刷新到主内存;这时候读线程去读取的话就可能读到旧数据。所以需要volatile来保证可见性。
- 变量不需要与其他的状态变量共同参与不变约束,例如low<up这样的场景就不行
- 在访问变量时需要使用锁,就不要使用volatile(《java并发编程实战》)
所以说,volatile只能实现部分线程安全(实际上只能实现可见性)。 如果volatile用得好的话,比synchronized强不少,因为不需要上下文切换。
注:
- 关于volatile禁止指令重排序的介绍去看《深入理解Java虚拟机(第二版)》第十二章"Java内存模型与线程"
- 通常情况下,能用volatile解决的就不去用synchronized了
附2 volatile的更多相关文章
- CopyOnWriteArrayList源码解析(1)
此文已由作者赵计刚授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 注:在看这篇文章之前,如果对ArrayList底层不清楚的话,建议先去看看ArrayList源码解析. ht ...
- ConcurrentHashMap源码解析(2)
此文已由作者赵计刚授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. ConcurrentHashMap() /** * 创建ConcurrentHashMap ...
- AtomicInteger源码解析
此文已由作者赵计刚授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 1.原子类 可以实现一些原子操作 基于CAS 下面就以AtomicInteger为例. 2.AtomicIn ...
- 第二章 ConcurrentHashMap源码解析
注:在看这篇文章之前,如果对HashMap的层不清楚的话,建议先去看看HashMap源码解析. http://www.cnblogs.com/java-zhao/p/5106189.html 1.对于 ...
- 第三章 CopyOnWriteArrayList源码解析
注:在看这篇文章之前,如果对ArrayList底层不清楚的话,建议先去看看ArrayList源码解析. http://www.cnblogs.com/java-zhao/p/5102342.html ...
- 第十一章 AtomicInteger源码解析
1.原子类 可以实现一些原子操作 基于CAS 下面就以AtomicInteger为例. 2.AtomicInteger 在没有AtomicInteger之前,对于一个Integer的线程安全操作,是需 ...
- KingbaseES CTID 与 Oracle ROWID
熟悉oracle的人都知道ROWID可用于快速的数据访问,KingbaseES 由于自身MVCC机制的原因,ctid 作为 oracle rowid 的替代方案不合适,但currtid 还是基本可以满 ...
- 为什么volatile不能保证原子性而Atomic可以?
在上篇<非阻塞同步算法与CAS(Compare and Swap)无锁算法>中讲到在Java中long赋值不是原子操作,因为先写32位,再写后32位,分两步操作,而AtomicLong赋值 ...
- 在ADS上由于volatile惹得祸
C语言关键字volatile是一个危险的东东,笔者再用ADS做S3C2440定时器中断实验就因为这个关键字出了错.出现错误情况的准确描述是:定义一个变量时没有用volatile关键字,而且紧接着whi ...
随机推荐
- Rakefile实例教程
一.简介 简单的说Rakefile就是使用Ruby语法的makefile, 对应make的工具就是rake. 在Ruby on Rails里面, 不管是数据库的初始化, 内容初始化, 删除, 还是测试 ...
- Java 8 Stream API
Java 8 Stream API JDK8 中有两大最为重要的改变.第一个是 Lambda 式:另外 Stream API(java.util.stream.*) Stream 是 JDK8 中处理 ...
- 【附源文件】日记类App原型制作分享-Grid Diary
Grid Diary是一款非常受文艺青年喜爱的记录应用,它设计简单,内容却非常丰富.它不再是单调的文字记录,界面的设计非常与众不同,由许多格子拼凑而成,每一个格子里面还带有一个问题,十分有趣.提到格子 ...
- asp.net状态保持
1.首先如果不是asp.net webform而只是一个纯粹的html页面和ashx一般处理程序的话,因为http协议的无状态,每一次的页面请求都会重新实例化一个页面对象(注意实例化页面对象其实是通过 ...
- RocketMQ的客户端连接数调查
RocketMQ版本:3.4.6 ==问题现象== RocketMQ集群的某个topic,在一部分节点上消费有“断层”,这部分数据一致没办法消费. ==调查过程== 一顿操作猛如虎的调查之后发现, 该 ...
- 12月6日 被引入的jsp 页面,引入 js 要注意结束符 要用 </script> 而不是 />
12月6日 被引入的jsp 页面,引入 js 要注意结束符 要用 </script> 而不是 />
- Json和XML解析
NSXMLParse 关于XML,有两种解析方式,分别是SAX(Simple API for XML,基于事件驱动的解析方式,逐行解析数据,采用协议回调机制)和DOM(Document Object ...
- AJAX学习必备三本书
<AJAX基础教程>AJAX必备图书之一.国内发行的第一本AJAX图书,也是目前最好的AJAX入门书,如果您是AJAX新手,此书是最好的入门图书.本书基本包括了实现Ajax需要了解的大部分 ...
- phalapi框架where条件查询
// WHERE name = 'dogstar' AND age = 18 $user->where(array('name' => 'dogstar', 'age' => 18) ...
- Django入门指南-第10章:Django Admin 介绍(完结)
在浏览器中打开该URL:http://127.0.0.1:8000/admin/ 我们可以检查一切是否正常,打开URL http://127.0.0.1:8000 我们首先创建一个管理员帐户: pyt ...