1. 概述

Java编程语言允许线程访问共享变量,为了确保共享变量能被准确和一致地更新, 线程可以通过排他锁单独获得这个变量。Java语言提供了volatile,在某些情况下比锁要更加方便。

volatile具有以下特性

  • 可见性:对于volatile变量,一个线程对它的修改,对其他线程是可见的。也就是说,任何线程读这个变量时,读到的都是最新值。
  • 原子性:volatile只能保证对单个变量读或写的原子性,对复合操作(比如i++)是不具有原子性的。

2. volatile的可见性

那么volatile的可见性是如何实现的呢?我们先来简单了解一下Java内存模型。(这部分内容参考《Java并发编程的艺术》)

在并发编程中,需要处理两个关键问题:线程之间如何通信、线程之间如何同步。通信是指线程之间以何种机制来交换信息,同步是指以何种机制来控制不同线程执行操作的相对顺序。Java采用的是共享内存模型,在此模型下,Java线程之间的通信是隐式进行的,整个通信过程对程序员完全透明;而同步是显式的,程序员必须显式地指定某些代码需要在线程之间互斥地进行。(这段可能比较抽象,不太理解也没关系,接着往下看)

在JVM的运行时数据区中,堆区和方法区是线程的共享区域,我们这里重点关注堆区。堆区存放着对象实例、静态于和数组元素,我们统称它们为共享变量。Java内存模型(JMM)规定,线程之间的共享变量存储在主内存中,每个线程的都有一个私有的本地内存(即该线程的工作内存),本地内存存放了该线程操作的共享变量的副本。本地内存是JMM的一个抽象概念,并不是真实存在的,它包括了缓存、写缓冲区、寄存器等。JMM的抽象结构示意图如下

对于没有被volatile修饰的变量,当线程要读共享变量时,会先判断此变量是否在CPU缓存中,如果在就从缓存读取,如果不在就从主内存读取并放入缓存中;当要写这个共享变量时,会写入到缓存中,而缓存中的数据会定期刷新到主内存中。这样就存在一个问题,对于共享变量x,假设线程A从主内存读取到x=0,将其修改为x=2,并写入缓存中,还没有刷新到主内存时,另一个线程B也来从主内存读取变量x,本来此时x已经被线程A修改为2了,但是B读到的依然是0。另一种情况是,假设线程A和B都缓存了变量x的副本x=0,现在A对其进行了修改x=2,并刷新到了主存,但是B在读取的时候依然从自己的缓存中读取,读到的是x=0。这就是因为不可见性而导致了不一致。也就是说,一个线程对共享变量x进行了修改,但是其他线程对此一无所知,依然在用原来的值。那么Java提供的volatile关键字是如何保证共享变量的可见性的呢?

volatile做了两件事

  • 如果线程对volatile变量进行了修改,那么此变量对应的缓存行会被立即刷新到主内存中;(这意味着主内存中的volatile变量总是最新值)
  • 这个刷新到住主内存的操作会使该变量在其他CPU中的缓存无效,也可以理解为使得其他线程工作内存中的该变量变的无效;(这意味着其他线程读这个变量时,不是从缓存中读,而是一定要从主内存中读)。这件事是通过MESI(缓存一致性协议)实现的。

那么,CPU是怎么发现这个数据失效了呢?答案是--嗅探

处理器使用嗅探技术保证它的内部缓存、系统内存和其他处理器的缓存数据在总线上保持一致。每个处理器通过嗅探在总线上传播的数据来检查自己缓存的值是不是过期了,当处理器发现自己缓存行对应的内存地址被修改,就会将当前处理器的缓存行设置成无效状态。

3. volatile的应用场景

要使 volatile 变量提供理想的线程安全,必须同时满足下面两个条件:

  • 对变量的写操作不依赖于当前值
  • 该变量没有包含在具有其他变量的不变式中。

这些条件表明,可以被写入 volatile 变量的这些有效值独立于任何程序的状态,包括变量的当前状态。当一个变量的值依赖于它之前的值时,volatile就无法工作了,如n=n+1,n++等。如果某个变量的值受到其他变量的值限制,那么volatile也无法工作,如Range类的lower和upper边界,必须遵循lower<=upper的限制。

场景1:状态标志

volatile boolean shutdownRequested;
...public void shutdown() { shutdownRequested = true;
}public void doWork() { while (!shutdownRequested) { // do stuff}
}

场景2:开销较低的“读锁”策略

@ThreadSafe
public class CheesyCounter {// Employs the cheap read-write lock trick// All mutative operations MUST be done with the 'this' lock held@GuardedBy("this") private volatile int value;//读操作,没有synchronized,提高性能public int getValue() { return value; } //写操作,必须synchronized。因为x++不是原子操作public synchronized int increment() {return value++;}

4. volatile和synchronized的区别

  • volatile只能修饰实例变量和类变量,而synchronized可以修饰方法,以及代码块。
  • volatile保证数据的可见性,仅保证了对volatile变量读和写操作的原子性;而synchronized是一种排他(互斥)机制,保证可见性和原子性。
  • volatile不会造成线程的阻塞,synchronized可能会造成线程的阻塞。

浅谈volatile的原理相关推荐

  1. 浅谈:Spring Boot原理分析,切换内置web服务器,SpringBoot监听项目(使用springboot-admin),将springboot的项目打成war包

    浅谈:Spring Boot原理分析(更多细节解释在代码注释中) 通过@EnableAutoConfiguration注解加载Springboot内置的自动初始化类(加载什么类是配置在spring.f ...

  2. 浅谈前端路由原理hash和history

    浅谈前端路由原理hash和history

  3. 浅谈“三层结构”原理与用意(转帖)

    浅谈"三层结构"原理与用意 序 在刚刚步入"多层结构"Web应用程序开发的时候,我阅读过几篇关于"asp.net三层结构开发"的文章.但其多 ...

  4. svc的参考文献_浅谈SVC的原理及作用

    浅谈 SVC 的原理及作用 超(特)高压运行检修公司 自贡中心 涂洪骏 摘要: 介绍了静止补偿器 (SVC) 的工作特性.基本原理.运行方式,重点针对 SVC 的作用进行了分析. 关键词 :静止补偿器 ...

  5. 浅谈Wi-Fi渗透--原理篇

    浅谈Wi-Fi渗透–原理篇 在这个手机比人多的移动时代,无线网络Wi-Fi遍布每个角落,殊不知隐藏其中的风云涌动 广义上无线网络应用类型如下,今天的文章就聚焦于 WLAN的一种无线局域网技术--Wi- ...

  6. 浅谈会话劫持原理及实践

    <监视你的一举一动> ---浅谈会话劫持原理及实践 前言 通常,大家所说的入侵,都是针对一台主机,在获得管理员权限后,就很是得意:其实,真正的入侵是占领整个内部网络.针对内部网络的攻击方法 ...

  7. 浅谈实时数据库系统原理及其应用

    浅谈实时数据库系统原理及其应用 孙俊彦   苏州大学计算机科学与技术学院 摘要: 现代的工程和时间关键型应用对数据库的实时性和对数据直接分析和处理的能力要求特别高,单纯的传统关系数据库已经不能满足需要 ...

  8. 浅谈Openstack网络原理(openstack无法上网?)

    浅谈Openstack网络 本版本为Stein版本,采用OVS网络 测试环境:1控制节点,2个计算节点 目录 浅谈Openstack网络 一.网络结构图 二.OVS分析 三.DHCP服务 四.Rout ...

  9. 浅谈volatile

    前言 提到volatile关键字的原理,我这里不想赘述,其实我也讲不好,因为这不是一篇简短的文章和我这个水平就能讲的清楚的,我建议你如果想了解一下volatile的原理,可以去看一下<Java并 ...

  10. 独家 | 浅谈强化学习原理(附代码链接)

    作者:Michel Kana 翻译:王琦 校对:王雨桐 本文约4900字,建议阅读15分钟. 本文介绍了强化学习的基本原理,并通过代码实例来讲解如何找到最优策略. Google在2017年年底发布了A ...

最新文章

  1. MySQL--5子查询与连接小结
  2. linux socket 错误 Connect error: No route to host(errno:113) 解决方法
  3. CTFshow php特性 web144
  4. lcd timing 先关参数
  5. python bootstrap-fileinput示例_bootstrapfileinput实现文件自动上传
  6. java 注解: Annotation
  7. QT每日一练day5:QLabel和按钮窗口打印功能
  8. 详解MAC硬盘中各个文件夹
  9. mysql备份的sql语句_Mysql主从备份和SQL语句的备份
  10. 运行在一个完全隔离环境中的完整计算机系统,凤凰系统完全释放PC性能 模拟器是指通过软件模拟具有完整硬件系统功能、运行在一个完全隔离环境中的计算机系统...
  11. 求和值大于等于776且和值最小的两个数
  12. python3编写方程计算器_python算法——方程计算器小工具
  13. usb3.0速度测试软件,USB3.0芯片速度测试比较
  14. FormData兼容性问题
  15. 用C语言做了一个外卖管理系统
  16. Python面向对象基础练习——设计一个名为 MyRectangle 的矩形类来表示矩形
  17. netty 多线程用一个长连接(channel) 发送消息 并发安全吗?
  18. 特斯拉改版Model3更便宜/ 贾跃亭又被申请限消/ GPT-3更新…今日更多新鲜事在此...
  19. XSL语言(XSL Languages)(1)XSL Languages
  20. ★Sql Server 2012 数据库修复一般性错误修复

热门文章

  1. insserv: warning: script 'lampp' missing LSB tags and overrides
  2. Google Play在GDC大会上发布全新工具及游戏
  3. 【实验五】利用三层交换机实现VLAN间路由
  4. linux-SSH远程服务的管理操作,查看虚拟机信息
  5. maven向本土仓库导入jar包(处理官网没有的jar包)
  6. 利用MVC思想和php语言写网站的心得
  7. Processing的条件式
  8. 【漫画】兔子,胡萝卜和屎
  9. [Unity]限制一个值的大小(Clamp以及Mathf)
  10. ExtJS TreeGrid的使用方法