volatile变量自身具有下列特性。
1.可见性。对一个volatile变量的读,总是能看到(任意线程)对这个volatile变量最后的写 入。 ·
2.原子性:对任意单个volatile变量的读/写具有原子性,但类似于volatile++这种复合操作不 具有原子性。
(PS:从JSR-133内存模型开始(即从JDK5开始),仅仅只允许把 一个64位long/double型变量的写操作拆分为两个32位的写操作来执行,任意的读操作在JSR133中都必须具有原子性(即任意读操作必须要在单个读事务中执行)。总结:64为的变量写操作可能会被拆分两个32位的写操作,不具备原子性,读操作是原子性)
volatile 单个变量的读写可看做使用了同一个锁对单个读写做了同步。
 
volatile写-读的内存语义(JMM为java内存模型):
有volatile变量修饰的共享变量进行写操作的时候被处理成汇编指令序列会多出Lock前缀的指令,Lock前缀的指令在多核处理器下会引发了两件事情。
1)将当前处理器缓存行的数据写回到系统内存。
2)这个写回内存的操作会使在其他CPU里缓存了该内存地址的数据无效。
1.当写一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量值刷新到主内 ,,实质上是线程A向接下来将要读这个volatile变量的某个线程 发出了(其对共享变量所做修改的)消息。
实现原则:Lock前缀指令会引起处理器缓存回写到内存:使用“缓存锁 定”,缓存一致性机制会阻止同时修改由两个以上处理器缓存的内存区域数据。
2.当读一个volatile变量时,JMM会把该线程对应的本地内存置为无效。线程接下来将从主 内存中读取共享变量。线程B读一个volatile变量,实质上是线程B接收了之前某个线程发出的(在写这个volatile 变量之前对共享变量所做修改的)消息。
实现原则:一个处理器的缓存回写到内存会导致其他处理器的缓存无效:处理器使用MESI(修改、独占、共享、无效)控制协议去维护内部缓存和其他处理器缓存的一致 性。
(ps:线程A写一个volatile变量,随后线程B读这个volatile变量,这个过程实质上是线程A通过 主内存向线程B发送消息。)
 

volatile内存语义的实现

JMM会限制编译器重排序和处理器对volatile语义重排序。

volatile重排序规则表:

1.当第二个操作是volatile写时,不管第一个操作是什么,都不能重排序。这个规则确保 volatile写        之前的操作不会被编译器重排序到volatile写之后。

2.当第一个操作是volatile读时,不管第二个操作是什么,都不能重排序。这个规则确保 volatile读之后的操作不会被编译器重排序到volatile读之前。

3.当第一个操作是volatile写,第二个操作是volatile读时,不能重排序。

为了实现volatile内存语义,编译器会在指令序列插入内存屏障来限制指令重排序。下面是基于保守策略的JMM内存屏障插入策略(关于内存屏障指令见文章末尾介绍):
1.在每个volatile写操作的前面插入一个StoreStore屏障。
2.在每个volatile写操作的后面插入一个StoreLoad屏障。
3.在每个volatile读操作的后面插入一个LoadLoad屏障。
4.在每个volatile读操作的后面插入一个LoadStore屏障。

volatile写插入内存屏障后生成的指令序列示意图:

这里比较有意思的是,volatile写后面的StoreLoad屏障。此屏障的作用是避免volatile写与 后面可能有的volatile读/写操作重排序。因为编译器常常无法准确判断在一个volatile写的后面 是否需要插入一个StoreLoad屏障(比如,一个volatile写之后方法立即return)。为了保证能正确 实现volatile的内存语义,JMM在采取了保守策略:在每个volatile写的后面,或者在每个volatile 读的前面插入一个StoreLoad屏障。从整体执行效率的角度考虑,JMM最终选择了在每个 volatile写的后面插入一个StoreLoad屏障。因为volatile写-读内存语义的常见使用模式是:一个 写线程写volatile变量,多个读线程读同一个volatile变量。当读线程的数量大大超过写线程时, 选择在volatile写之后插入StoreLoad屏障将带来可观的执行效率的提升。

volatile读插入内存屏障后生成的指令序列示意图:


上述volatile写和volatile读的内存屏障插入策略非常保守。在实际执行时,只要不改变 volatile写-读的内存语义,编译器可以根据具体情况省略不必要的屏障。下面通过具体的示例 代码进行说明。

针对readAndWrite()方法,编译器在生成字节码时可以做如下的优化。

内存屏障类型表:

java关键字volatile内存语义详细分析的更多相关文章

  1. java多线程03-----------------volatile内存语义

    java多线程02-----------------volatile内存语义 volatile关键字是java虚拟机提供的最轻量级额的同步机制.由于volatile关键字与java内存模型相关,因此, ...

  2. java 关键字volatile

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

  3. 深入汇编指令理解Java关键字volatile

    volatile是什么 volatile关键字是Java提供的一种轻量级同步机制.它能够保证可见性和有序性,但是不能保证原子性 可见性 对于volatile的可见性,先看看这段代码的执行 flag默认 ...

  4. JAVA关键字Volatile的特性

    一.简述: 关键字Volatile是JAVA虚拟机提供的最轻量级的同步机制,但是它并不容易完全被正确.完整的理解,以致于许多程序员在遇到需要处理多线程数据竞争的时候一律使用synchronized来进 ...

  5. volatile内存语义

    全面理解Java内存模型(JMM)及volatile关键字 volatile的内存语义 Volatile读写所建立的happens-before关系Volatile读写的内存语义 锁: 获取和释放Vo ...

  6. Java 关键字volatile的解释

    volatile 关键字特征: 1.可见性,是指线程之间的可见性,一个线程修改的状态对另一个线程是可见的.可以禁止线程的工作内存对volatile修饰的变量进行缓存,并将修改的变量立即写入主存. 2. ...

  7. Java关键字-volatile

    关键字volatile可以说是Java虚拟机提供的最轻量级的同步机制. 一旦某个共享变量(类的成员变量.类的静态成员变量)被volatile修饰之后,那么就具备了两层语义: 1.保证了不同线程对这个变 ...

  8. 内存屏障和volatile内存语义的实现

    趁周末,把以前的书拿出来,再翻一番,顺便做个笔记: 内存屏障:用来控制和规范cpu对内存操作的顺序的cpu指令. 内存屏障列表: 1.loadload:确保“前者数据装载”先于“后者装载指令”: 2. ...

  9. 关于 Java 关键字 volatile 的总结

    1 什么是 volatile volatile 是 Java 的一个关键字,它提供了一种轻量级的同步机制.相比于重量级锁 synchronized,volatile 更为轻量级,因为它不会引起线程上下 ...

随机推荐

  1. C# WINFORM进销存系统开发(内涵免费源码+部分实操视频讲解)

    互联网的时代,电商火爆,大家都开始进行线上销售货品,那你是如何管理你的商品库存和进销问题?软积木--小敏用的是C# WINFORM进销存系统来管理我的数据,给我带来了很多便利. 它是高频需求项目,很多 ...

  2. 【JAVA】笔记(2)---面向过程与面向对象;类,对象;实例变量,引用;构造方法;

    面向过程与面向对象: 1.面向过程思想的典型栗子是C语言,C语言实现一个程序的流程是:在主函数中一步一步地罗列代码(定义子函数来罗列也是一样的道理),以此来实现我们想要的效果: 2.面向对象思想的典型 ...

  3. Python基础(filter)

    arr = [1,2,3,1,1,3,6,9] def f1(x): if x > 2: return True arr1 = list(filter(f1,arr)) print(arr1)# ...

  4. Python 爬取妹子图(技术是无罪的)

    ... import requests from bs4 import BeautifulSoup import os import sys class mzitu(): def html(self, ...

  5. [hdu6978]New Equipments II

    显然可以费用流来做,具体建图如下-- 点集:源点,汇点,左边$n$​个工人,右边$n$​​​个设备 边集:源点向第$i$​个工人连$(1,a_{i})$​的边,第$i$​个设备向汇点连$(1,b_{i ...

  6. java实现自动化发布平台核心代码

    1.搭建jenkins环境 (1)jenkins官网下载jenkins.war包 (2)将该war包放入到tomcat的webapp的目录下(前提条件需要配置tomcat的环境,详情请自行百度) (3 ...

  7. 网络协议之:一定要大写的SOCKS

    目录 简介 SOCKS的故事 SOCKS的历史 SOCKS协议的具体内容 SOCKS4 SOCKS4a SOCKS5 总结 简介 很久很久以前,人们还穿的是草鞋,草鞋虽然穿着舒服,但是不够美观.然后人 ...

  8. 【CSP2019 D1T2】【括号树】

    题面 不再多说,想必大家都看过这个题 思路 我们可以手推几个满足条件的字符串 我们发现在这些字符串里 每个)都与离它最近的(的匹配 所以我们维护树上每个节点到根节点中没用使用过的(的位置(nl[n]) ...

  9. FJD1T3(LOJ 2773 学习轨迹)

    发现了\(FJOI\)原题 没什么想法,想到自己考场上连\(n^2\)做法都不会就很感慨. 考虑如果只选择一个序列的任务,那么肯定全部选择会更加优秀. 那么考虑如果我们选择了两个序列的一部分. 如果\ ...

  10. Educational Codeforces Round 89 题解

    昨晚简单 vp 了场比赛找了找状态,切了 5 个题(有一个差点调出来),rk57,还算理想吧,毕竟我已经好久没碰过电脑了( A 签到题不多说,直接输出 \(\min\{a,b,\dfrac{a+b}{ ...