3.volatile能保证有序性吗?

  在前面提到volatile关键字能禁止指令重排序,所以volatile能在一定程度上保证有序性。

  volatile关键字禁止指令重排序有两层意思:

  1)当程序执行到volatile变量的读操作或者写操作时,在其前面的操作的更改肯定全部已经进行,且结果已经对后面的操作可见;在其后面的操作肯定还没有进行;

  2)在进行指令优化时,不能将在对volatile变量访问的语句放在其后面执行,也不能把volatile变量后面的语句放到其前面执行。

  可能上面说的比较绕,举个简单的例子:

1
2
3
4
5
6
7
8
//x、y为非volatile变量
//flag为volatile变量
x = 2;        //语句1
y = 0;        //语句2
flag = true;  //语句3
x = 4;         //语句4
y = -1;       //语句5

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

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

  那么我们回到前面举的一个例子:

1
2
3
4
5
6
7
8
9
//线程1:
context = loadContext();   //语句1
inited = true;             //语句2
//线程2:
while(!inited ){
  sleep()
}
doSomethingwithconfig(context);

  前面举这个例子的时候,提到有可能语句2会在语句1之前执行,那么久可能导致context还没被初始化,而线程2中就使用未初始化的context去进行操作,导致程序出错。

  这里如果用volatile关键字对inited变量进行修饰,就不会出现这种问题了,因为当执行到语句2时,必定能保证context已经初始化完毕。

4.volatile的原理和实现机制

  前面讲述了源于volatile关键字的一些使用,下面我们来探讨一下volatile到底如何保证可见性和禁止指令重排序的。

  下面这段话摘自《深入理解Java虚拟机》:

  “观察加入volatile关键字和没有加入volatile关键字时所生成的汇编代码发现,加入volatile关键字时,会多出一个lock前缀指令”

  lock前缀指令实际上相当于一个内存屏障(也成内存栅栏),内存屏障会提供3个功能:

  1)它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成;

  2)它会强制将对缓存的修改操作立即写入主存;

  3)如果是写操作,它会导致其他CPU中对应的缓存行无效。

五.使用volatile关键字的场景

  synchronized关键字是防止多个线程同时执行一段代码,那么就会很影响程序执行效率,而volatile关键字在某些情况下性能要优于synchronized,但是要注意volatile关键字是无法替代synchronized关键字的,因为volatile关键字无法保证操作的原子性。通常来说,使用volatile必须具备以下2个条件:

  1)对变量的写操作不依赖于当前值

  2)该变量没有包含在具有其他变量的不变式中

  实际上,这些条件表明,可以被写入 volatile 变量的这些有效值独立于任何程序的状态,包括变量的当前状态。

  事实上,我的理解就是上面的2个条件需要保证操作是原子性操作,才能保证使用volatile关键字的程序在并发时能够正确执行。

  下面列举几个Java中使用volatile的几个场景。

1.状态标记量

volatile boolean flag = false;
while(!flag){
    doSomething();
}
public void setFlag() {
    flag = true;
}


volatile
 boolean inited = false;

//线程1:
context = loadContext();  
inited = true;            
//线程2:
while(!inited ){
sleep()
}
doSomethingwithconfig(context);


2.double check

class Singleton{
    private volatile static Singleton instance = null;
     
    private Singleton() {
         
    }
     
    public static Singleton getInstance() {
        if(instance==null) {
            synchronized (Singleton.class) {
                if(instance==null)
                    instance = new Singleton();
            }
        }
        return instance;
    }
}

出处:http://www.cnblogs.com/dolphin0520/ 作者:海子 

本博客中未标明转载的文章归作者海子和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

转载于:https://blog.51cto.com/10414498/1844822

volatile关键字(三)相关推荐

  1. 三 volatile关键字

    一:内存模型: 大家都知道,计算机在执行程序时,每条指令都是在CPU中执行的,而执行指令过程中,势必涉及到数据的读取和写入.由于程序运行过程中的临时数据是存放在主存(物理内存)当中的,这时就存在一个问 ...

  2. [Java并发编程(三)] Java volatile 关键字介绍

    [Java并发编程(三)] Java volatile 关键字介绍 摘要 Java volatile 关键字是用来标记 Java 变量,并表示变量 "存储于主内存中" .更准确的说 ...

  3. java中实现具有传递性吗_Java中volatile关键字详解,jvm内存模型,原子性、可见性、有序性...

    一.Java内存模型 想要理解volatile为什么能确保可见性,就要先理解Java中的内存模型是什么样的. Java内存模型规定了所有的变量都存储在主内存中.每条线程中还有自己的工作内存,线程的工作 ...

  4. volatile关键字之全面深度剖析

    引言 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在Java 5之后,volatile关键字 ...

  5. c语言中volatile关键字的作用

    读文章之前 可以先看一下<程序员的自我修养 >第28页 过度优化. volatile 提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直 ...

  6. C语言volatile关键字详解

    volatile提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据.如果没有volatile关键字,则编译器可能优化读取和存储 ...

  7. 爆赞,对 volatile 关键字讲解最好的一篇文章!

    欢迎关注方志朋的博客,回复"666"获面试宝典 最近,在一篇文章中了解到了 volatile 关键字,在强烈的求知欲趋使下,我查阅了一些相关资料进行了学习,并将学习笔记记录如下,希 ...

  8. Java并发编程:JMM和volatile关键字

    Java内存模型 随着计算机的CPU的飞速发展,CPU的运算能力已经远远超出了从主内存(运行内存)中读取的数据的能力,为了解决这个问题,CPU厂商设计出了CPU内置高速缓存区.高速缓存区的加入使得CP ...

  9. c#中volatile关键字的作用

    恐怕比较一下volatile和synchronized的不同是最容易解释清楚的.volatile是变量修饰符,而synchronized则作用于一段代码或方法:看如下三句get代码: int i1;  ...

最新文章

  1. 安装Windows 64 位 mysql 最新版本解压包中没有data目录和my-default.ini及服务无法启动的快速解决办法...
  2. springboot 拦截器 日志_跟武哥一起学习Spring Boot,一份全面详细的学习教程
  3. Bzoj 2749: [HAOI2012]外星人 欧拉函数,数论,线性筛
  4. PAT——1074. 宇宙无敌加法器(20)
  5. startActivity流程(上)
  6. SQL里变量的声明以及常用函数举例
  7. Hadoop-2.6.0NodeManager Restart Recover实现分析(一)
  8. 「非推广」为什么我说本是设计师专属的『数位板』,也是程序猿+科研狗的开会神器?
  9. python opencv3 —— 常用工具、辅助函数、绘图函数(图像添加文本、矩形等几何形状)
  10. 解决jpa和hibernate的json序列化死循环问题
  11. bzoj1076 奖励关(概率dp)(状态压缩)
  12. python下载股票数据_如何下载股票历史数据?
  13. 用python实现遗传算法
  14. HFSS----微带天线设计实例之模型分析优化
  15. Landlock:一种新型Linux安全模块
  16. matlab检验数据异方差,求教!怀特异方差检验方法在matlab中的实现,以及广义最小平方法...
  17. 启动mongodb报错:waiting for connections on port 27017 解决方案
  18. C语言手机通讯录系统
  19. 九宫怎么排列和使用_剪映零基础入门教程第三十七篇:一学就会系列之九宫格小程序配音...
  20. 如何给SolidWorks工程图添加条型码?

热门文章

  1. 接口隔离原则最直白描述
  2. 链表一元多项式计算器的实现(Java语言描述)
  3. 二调建设用地地类代码_二调土地地类代码表
  4. npm install react-native-video --save
  5. XamarinAndroid组件教程设置自定义子元素动画(二)
  6. Xamarin.Forms教程开发的Xcode的下载安装
  7. python中self_一个例子带你入门Python装饰器
  8. oracle编程艺术在线,oracle编程艺术笔记-1
  9. 主机通过sftp传输文件到某台服务器ubuntu虚拟机出现:open for write: permission denied
  10. php sql alert,SQL ALTER