volatile关键字的两层语义
  一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:
  1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。
  2)禁止进行指令重排序。
根据volatile的语义,我们可以看到,volatile主要针对的是并发三要素(原子性,可见性和有序性)中的后两者有实际优化作用。
可见性:
  线程本身并不直接与主内存进行数据的交互,而是通过线程的工作内存来完成相应的操作。这也是导致线程间数据不可见的本质原因。因此要实现volatile变量的可见性,直接从这方面入手即可。对volatile变量的写操作与普通变量的主要区别有两点:

  (1)修改volatile变量时会强制将修改后的值刷新的主内存中。
  (2)修改volatile变量后会导致其他线程工作内存中对应的变量值失效。因此,再读取该变量值的时候就需要重新从读取主内存中的值。
  通过这两个操作,就可以解决volatile变量的可见性问题。
有序性:
  volatile会触发jvm的内存屏障策略
  
内存屏障策略:
(1)LoadLoad 屏障
  执行顺序:Load1—>Loadload—>Load2
  确保Load2及后续Load指令加载数据之前能访问到Load1加载的数据。
(2)StoreStore 屏障
  执行顺序:Store1—>StoreStore—>Store2
  确保Store2以及后续Store指令执行前,Store1操作的数据对其它处理器可见。
(3)LoadStore 屏障
  执行顺序: Load1—>LoadStore—>Store2
  确保Store2和后续Store指令执行前,可以访问到Load1加载的数据。
(4)StoreLoad 屏障
  执行顺序: Store1—> StoreLoad—>Load2
  每次对volatile进行读写操作,根据上述表格,会触发对应的CPU指令,从线程内存缓冲区将之前更改的变量刷入主存。
  简单来说,volatile会在一定程度上影响jvm指令集的优化策略,在volatile之前和之后的指令集不会乱序越过volatile变量执行。暂时volatile之前和之后的指令集在没有关联性的前提下,jvm可以乱序执行。
  jvm的volatile策略,在一定程度上,打折扣地实现了jvm的happens-before原则(先行发生原则),如下所述。
 
  • 程序次序规则:一个线程内,按照代码顺序,书写在前面的操作先行发生于书写在后面的操作
  • 锁定规则:一个unLock操作先行发生于后面对同一个锁额lock操作
  • volatile变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作
  • 传递规则:如果操作A先行发生于操作B,而操作B又先行发生于操作C,则可以得出操作A先行发生于操作C
  • 线程启动规则:Thread对象的start()方法先行发生于此线程的每个一个动作
  • 线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生
  • 线程终结规则:线程中所有的操作都先行发生于线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值手段检测到线程已经终止执行
  • 对象终结规则:一个对象的初始化完成先行发生于他的finalize()方法的开始

volatile常见使用场景:

(1)状态标记量

(2)单例模式一次性安全发布

(3)低开销读写锁

参考文档:
《Java并发编程:Volatile关键字解析》http://www.cnblogs.com/dolphin0520/p/3920373.html
《Java多线程:volatile变量,happens-before关系及内存一致性》http://www.importnew.com/17149.html
《Java并发编程:volatile的使用及其原理》http://www.cnblogs.com/paddix/p/5428507.html
《Java理论与实践:正确使用Volatile变量》https://www.ibm.com/developerworks/cn/java/j-jtp06197.html

Java并发编程 Volatile关键字解析的更多相关文章

  1. Java 并发:volatile 关键字解析

    摘要: 在 Java 并发编程中,要想使并发程序能够正确地执行,必须要保证三条原则,即:原子性.可见性和有序性.只要有一条原则没有被保证,就有可能会导致程序运行不正确.volatile关键字 被用来保 ...

  2. java并发系列(六)-----Java并发:volatile关键字解析

    在 Java 并发编程中,要想使并发程序能够正确地执行,必须要保证三条原则,即:原子性.可见性和有序性.只要有一条原则没有被保证,就有可能会导致程序运行不正确.volatile关键字 被用来保证可见性 ...

  3. Java并发编程volatile关键字

    volatile理解 Java语言是支持多线程的,为了解决线程并发的问题,在语言内部引入了 同步块 和volatile 关键字机制.volatile具有synchronized关键字的“可见性”,vo ...

  4. java并发编程 volatile关键字 精准理解

    1.volatile的作用 一个线程共享变量(类的成员变量.类的静态成员变量等)被volatile修饰之后,就具有以下作用: 1)并发中的变量可见性(不同线程对该变量进行操作时的可见性),即一个线程修 ...

  5. 一起来看看java并发中volatile关键字的神奇之处

    并发编程中的三个概念: 1.原子性 在Java中,对基本数据类型的变量的读取和赋值操作是原子性操作,即这些操作是不可被中断的,要么执行,要么不执行. 2.可见性 对于可见性,Java提供了volati ...

  6. java并发:volatile关键字

    java并发需要保证原子性,可见性,有序性. http://www.cnblogs.com/expiator/p/9226775.html 一.volatile关键字作用如下: 1.volatile关 ...

  7. Java 并发编程——volatile与synchronized

    一.Java并发基础 多线程的优点 资源利用率更好 程序设计在某些情况下更简单 程序响应更快 这一点可能对于做客户端开发的更加清楚,一般的UI操作都需要开启一个子线程去完成某个任务,否者会容易导致客户 ...

  8. Java多线程编程——volatile关键字

    (本篇主要内容摘自<Java多线程编程核心技术>) volatile关键字的主要作用是保证线程之间变量的可见性. package com.func; public class RunThr ...

  9. Java并发编程--Volatile详解

    摘要      Volatile是Java提供的一种弱同步机制,当一个变量被声明成volatile类型后编译器不会将该变量的操作与其他内存操作进行重排序.在某些场景下使用volatile代替锁可以减少 ...

随机推荐

  1. 理解最基本的Vue项目

    上一篇<Vue开发环境搭建及热更新>,我们讲解了vue开发环境的搭建还有一些小问题,接下来我们来讲解一下这个界面是如何形成的. 在开始讲之前,我们先来看看我们上一篇所谓的项目目录里面到底放 ...

  2. windows越用越卡怎么办?(转)

    方法一 1.按快捷键"win+R" 打开 运行窗口 2.这时候输入"msconfig"后 ,点击"确定"或者按"ENTER&quo ...

  3. (转)CentOS无损调整磁盘分区大小的实现方法

    前几天在QQ群里,有一个朋友问到关于Linux中如何无损调整磁盘分区大小的问题,针对这个问题我在实际使用的过程中也曾探索过,所以比较关注如何无损的调整磁盘分区大小,而不丢失数据!在Windows中,我 ...

  4. c语言 内存管理

    动态内存是由程序员手动分配,不再使用时,一定记得释放内存. 静态内存是程序开始运行时由编译器分配的内存,它的分配是程序开始编译时完成的,不占用cpu资源.程序中的各种变量在编译源程序时就已经分配了内存 ...

  5. Andrew Ng机器学习课程笔记--week10(优化梯度下降)

    本周主要介绍了梯度下降算法运用到大数据时的优化方法. 一.内容概要 Gradient Descent with Large Datasets Stochastic Gradient Descent M ...

  6. 4_SSRF

    SSRF SSRF(服务请求伪造)是一种由攻击者构造形成由服务器端发起请求的一个安全漏洞,它将一个可以发起网络请求的服务当作跳板来攻击其他服务器,SSRF的攻击目标一般是内网.当服务器提供了从其他服务 ...

  7. Html5笔记之第六天

    Canvas元素 <canvas> 标签定义图形,比如图表和其他图像,您必须使用脚本来绘制图形. 在画布上(Canvas)画一个红色矩形,渐变矩形,彩色矩形,和一些彩色的文字. <c ...

  8. Linux下检测进程是否存在

    这个问题看起来好像很简单,"ps -ef | grep xx"一下就行啦!这样做当然可以,但是如果我们考究起性能来,这恐怕不是个好办法. 假设我们现在要监测某进程是否存活,每分钟检 ...

  9. oracle语句批处理

    数据量有40万条,从一个对象table_01一条一条取数到对象table_02,如果用原始的 Statement Statmt =comm.createStatement(); String sql= ...

  10. jackjson和fastjson进行Bean与json互换

    1.jackjson 1.bean到json ObjectMapper m = new ObjectMapper(); String value = m.writeValueAsString(bean ...