volatile关键字是如何起作用的?
关键字volatile是Java虚拟机提供的最轻量级的同步机制,但是在平时的项目里面,遇到需要多线程的时候更多地使用的是synchronized关键字来进行同步。个人而言,更多的原因是对volatile关键字的机制不了解导致的。
Java内存模型对volatile专门定义了一些特殊的访问规则,当一个变量定义为volatile之后便具有了两种特性:
1. 保证此变量对所有线程的可见性,“可见性”指当一条线程修改了这个变量的值,新的值对与其他线程来说是立即得知的。
2. 禁止指令重排序优化。
接下来将对上述两个方面分别介绍:
普通变量的值在县城之间传递均需要通过主内存来完成,例如,线程A修改一个普通变量的值,然后向内存进行会写,另外一条线程B在线程A回写完之后再从主内存中进行读取操作,新变量值才会对线程B可见。
尽管volatile定义的变量对所有的线程都是可见的,但是并不能说明volatile定义的变量的运算在并发下就是安全的。
(在各个线程的工作内存中,volatile变量也可以存在不一致的情况,但是由于每次使用之前都已经刷新了,执行引擎看不到不一致的情况,所以便认为不存在不一致的情况)
导致不安全的原因其实还是Java运算是非原子操作。所谓原子操作是指操作的执行不会被线程的调度给打断。
可以看这个例子:
public class VolatileTest {
public static volatile int race = 0;
public static void increase(){
race++;
}
private static final int THREAD_COUNT = 20;
public static void main(String[] args) {
Thread[] threads = new Thread[THREAD_COUNT];
for(int i = 0; i < THREAD_COUNT; i++){
threads[i] = new Thread(new Runnable() {
@Override
public void run() {
for(int i = 0; i < 1000; i++){
increase();
}
}
});
threads[i].start();
}
while(Thread.activeCount() > 1){
Thread.yield();
}
System.out.println(race);
}
}
20个线程,每个线程会对race变量进行1000次自增操作,即race++。输出的结果应该是20000,但是会发现每次运行的结果都不一样,而且都是一个小于20000的数。
导致的原因是race++操作并不是一个原子操作,尽管看来它只有一句话,但是在编译时并不是这样的。用javap命名进行反编译,同时输出附加信息:

increase()方法的执行一共是四条字节码指令完成的,熟悉字节码命令的可以看出着四步的操作,
当getstatic指令将race的值取到操作栈的时候,volatile保证了race的值是正确的,但是在执行后面的指令的时候,其它的线程可能已经把race的值修改了。
即使编译出来的只有一条字节码指令,但也不意味这是一个原子操作。
由于volatile变量智能保证可见性,依然需要synchronized和java.util.concurrent中的原子类来保证线程的安全。
下面这段代码就展示了一个很好的volatile的使用场景:
volatile Boolean shutdownRequset;
public void shutdown() {
shutdownRequset = true;
}
public void doWork() {
while(!shutdownRequest){
...
}
}
当shutdown()方法被调用的时候,能保证所用的doWork()方法都停下来。
——————————————————————————————————————————————————————————————————————
接下来是第二个方面的用途,普通变量仅仅会保证在该方法执行过程中所有依赖赋值结果的地方都能获得正确的结果,而不能保证变量赋值的操作顺序与程序代码的执行顺序一致。
如果定义的变量没有被volatile修饰,那么就有可能由于指令重排的优化而导致执行顺序的颠倒。
如下面这段代码:
public class Singleton {
private volatile static Singleton instance;
public static Singleton getInstance(){
if(instance == null){
synchronized (Singleton.class) {
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
public static void main(String[] args) {
Singleton.getInstance();
}
}
通过JIT编译之后就会多执行一个“lock”操作,这个操作相当于一个内存屏障,指重排序之后,不能讲屏障之后的操作放到屏障之前。
不过说到底并不能说volatile有什么执行的迅速的特点,但其开销是比锁低的,,唯一需要看的是volatile是否满足使用场景。
volatile关键字是如何起作用的?的更多相关文章
- 实习第一个月总结(const关键字、条件编译、volatile关键字、#和##的作用、函数指针)
C语言中const关键字的作用: 修饰局部变量或者全局变量,表示变量n的值不能被改变了 修饰指针,分为常量指针与指针常量,也可以两者结合 常量指针指向的值不能改变,但是这并不是意味着指针本身不能改变, ...
- Volatile关键字的两个作用
1.保证修饰的变量对所有线程的可见性,这里的“可见性”是指当一条线程修改了这个值,新值对于其他线程来说是可以立即得知的. 2.禁止指令重新排序化
- [其他]volatile 关键字
用 volatile 关键字修饰函数 的作用是 告诉编译器该函数不会返回 , 让编译器能产生更好的代码 另外也能避免一些假警告信息,如未初始化的变量等
- [面试必备]深入理解Java的volatile关键字
前言 在Java并发编程中,volatile关键字有着至关重要的作用,在面试中也常常会是必备的一个问题.本文将会介绍volatile关键字的作用以及其实现原理. volatile作用 volatile ...
- Volatile关键字回顾之线程可见性
java中,volatile关键字有两大作用: 1.保证线程的可见性 2.防止指令重排序 这篇文章主要通过典型案例,体现可见性这一特性. 概念: java中,堆内存是线程共享的.而每个线程,都应该有自 ...
- Java并发编程——为什么要用volatile关键字
首发地址 https://blog.leapmie.com/archives/66ba646f/ 日常编程中出现 volatile 关键字的频率并不高,大家可能对 volatile 关键字比较陌生,再 ...
- 深入解析volatile关键字
前言 很高兴遇见你~ 欢迎阅读我的文章. volatile关键字在Java多线程编程编程中起的作用是很大的,合理使用可以减少很多的线程安全问题.但其实可以发现使用这个关键字的开发者其实很少,包括我自己 ...
- 【面试普通人VS高手系列】volatile关键字有什么用?它的实现原理是什么?
一个工作了6年的Java程序员,在阿里二面,被问到"volatile"关键字. 然后,就没有然后了- 同样,另外一个去美团面试的工作4年的小伙伴,也被"volatile关 ...
- Java并发编程学习笔记 深入理解volatile关键字的作用
引言:以前只是看过介绍volatile的文章,对其的理解也只是停留在理论的层面上,由于最近在项目当中用到了关于并发方面的技术,所以下定决心深入研究一下java并发方面的知识.网上关于volatile的 ...
随机推荐
- 封装及propery的使用
封装 封装的目的 使类中的属性或者方法只允许在类内部使用,不允许外部对其访问,保证数据的安全性. 封装的方法 使属性或者函数名改写成:"__属性名或者函数名"的格式,即完成了对本类 ...
- 自动类型安全的.NET标准REST库refit
在SCOTT HANSELMAN 博客上看到一个好东西<Exploring refit, an automatic type-safe REST library for .NET Standar ...
- 异步编程Async/await关键字
异步编程Async \await 关键字在各编程语言中的发展(出现)纪实. 时间 语言版本 2012.08.15 C#5.0(VS2012) 2015.09.13 Python 3.5 2016.03 ...
- extjs 关于dom操作的几个库
经过几天的学习研究,发现ext与jquery的设计思路完全是来自两个方向. jquery是内聚,把所有东西都放在$的下面,而ext是采用分模块的设计思路,每个功能封装一个库.这样就形成了各自的实用风格 ...
- Web Api 基于Zookeeper的服务注册与发现
安装与差异 Zookeeper安装请参考我上篇文章 http://www.cnblogs.com/woxpp/p/7700368.html 基于Nginx的服务提供和消费 基于zookeeper的服务 ...
- 从durable谈起,我是如何用搜索引擎抓住技术的关键字学习新姿势打开敏捷开发的大门
---又名我讨厌伸手党 我又把个人博客的子标题改为了 你可以在书和搜索引擎找到90%的问题的答案,为什么要问别人?剩下的10%或许没有答案,为什么要问别人? 这是由于最近在网上看到各种伸手,对于我这种 ...
- 大数据:Hadoop入门
大数据:Hadoop入门 一:什么是大数据 什么是大数据: (1.)大数据是指在一定时间内无法用常规软件对其内容进行抓取,管理和处理的数据集合,简而言之就是数据量非常大,大到无法用常规工具进行处理,如 ...
- java 的equals 与== ,null与isempty的区别
1 . == 是为了判断等号两边 变量 所对应 的 内存中的 值 是否 相等, 只是 值 的比较. 2. 假如 String s1 = new String("abc") ...
- 黑马day16 jquery&内容过滤选择器&可见度选择器
内容过滤选择器的过滤规则主要体如今它所包括的子元素和文本内容上 .:contains(text) 使用方法: $("div:contains('John')") 返回值 集 ...
- File attachment or query results size exceeds allowable value of 1000000 bytes.
今天早晨,收到了作业执行失败的邮件(前几天还能正常执行该作业.不知为何今天出错) 邮件显示,作业的第三个步骤报错. step3内容: msdb.dbo.sp_send_dbmail @prof ...