简述

volatile 是轻量级的synchronized,在多线程开发中保证了共享变量的可见性。可见性就是当一个线程修改一个共享变量时,另一个线程可以读到修改的值。如果volatile变量使用恰当,它比synchronized的使用成本更低,因为它不会引起线程上下文的切换和调度。

什么是volatile

Java语言提供了一种稍弱的同步机制,即 volatile 变量,用来确保共享变量能被多线程正确的更新和读取。当把变量声明为volatile后,编译器和运行时就会认为这个变量是共享的,因此不会把该变量的操作和其他内存操作一起重排序。volatile 变量不会被缓存在寄存器或者其他处理器不可见的地方,因此在读取volatile 修饰的变量时总会返回最新的值。

volatile 的实现原理

在了解volatile 的实现原理之前,我们先看一下与其相关的CPU术语:

术语 英文名称 术语描述
内存屏障 memory barriers 一组处理器指令,用来限制对内存操作的顺序
缓冲行 cache line 缓存中可以分配的最小存储单位,处理器在填写缓存行时,会加载整个缓存行,需要多个主内存读周期
原子操作 automic operations 不可中断的一个或一系列操作
缓冲行填充 cache line fill 当处理器识别到从内存中读取的操作数是可以缓存的,处理器会读取整个缓存行到适当的缓存(L1,L2,L3)
缓存命中 cache hit 处理器从缓存中读取到了需要的数据
写命中 write hit 当处理器将操作数写会到缓存区域时,会先检查这个缓存的内存地址是否在缓存行中,如果存在一个有效的缓存行,则处理器将这个操作数写回到缓存,而不是写到内存,这个操作被称为 写命中
写缺失 write misses the cache 一个有效的缓存行被写到不存在的内存区域

volatile 如何保证可见性

为了提高处理速度,处理器不直接和内存进行通信,而是先将系统内存的数据读到内部缓存(L1,L2,L3或其他)后再进行操作,但是操作完不知道何时会被写到内存。

如果对声明了volatile 的变量进行写操作,JVM 就会向处理器发送一条Lock前缀的指令,将这个变量所在缓存行的数据写回到系统内存。

在多核处理器下,为了保证各个处理器的缓存是一致的,就会实现缓存一致性协议,每个处理器通过嗅探在总线上传播的数据来检查自己缓存的值是否过期,当处理器发现自己缓存行对应的内存地址被修改,就会将当前处理器的缓存行设置成无效状态,当处理器对这个数据进行修改操作的时候,会重新从系统内存中把数据读到处理器缓存里。

volatile 实现原则

1、Lock 前缀的指令会引起处理器缓存回写到内存

如果访问的内存区域已经缓存在处理器内部,此时当前处理器会锁定这块内存区域的缓存并写到内存,并使用缓存一致性机制来确保修改的原子性,此操作被称为 缓存锁定,缓存一致性机制会阻止同一时间修改两个以上处理器缓存的内存区域的数据。

2、一个处理器的缓存回写到内存会导致其他处理器的缓存失效

处理器使用嗅探技术保证它的内部缓存、系统内存 和 其他处理器的缓存的数据在总线上保持一致。如果通过嗅探一个处理器来检测其他处理器打算写内存地址,而这个内存地址当前处于共享状态,那么正在嗅探的处理器将使它的缓存行无效,在下次访问相同内存地址是,强制执行缓存行填充。

volatile 的局限性

虽然volatile变量使用很方便,但也存在一些局限性。volatile变量通常用作某个操作完成、发生中断或者状态的标志。尽管volatile 变量也可以用于表示其他的状态信息,但在使用时要非常小心。例如:volatile 的语义不足以确保递增操作(count++)的原子性,除非能确保只有一个线程对变量进行写操作。

加锁机制既可以确保可见性又可以确保原子性,而volatile 变量只能确保可见性。

当满足以下所有条件时,才应该使用volatile 变量:

1、对变量的写入操作不依赖于变量的当前值,或者确保只有一个线程更新变量的值

2、该变量不会与其它变量一起作为不变性条件

3、在访问变量时不需要加锁

Java关键字volatile的实现原理(四)的更多相关文章

  1. java 关键字volatile

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

  2. JAVA关键字Volatile的特性

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

  3. Java 关键字volatile的解释

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

  4. Java关键字-volatile

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

  5. java关键字volatile用法详解

    volatile关键字想必大家都不陌生,在java 5之前有着挺大的争议,在java 5之后才逐渐被大家接受,同时作为java的关键字之一,其作用自然是不可小觑的,要知道它是java.util.con ...

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

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

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

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

  8. Java内存模型及Java关键字 volatile的作用和使用说明

    先来看看这个关键字是什么意思:volatile  [ˈvɒlətaɪl] adj. 易变的,不稳定的; 从翻译上来看,volatile表示这个关键字是极易发生改变的.volatile是java语言中, ...

  9. Java 关键字volatile 与 synchronized 作用与区别

     1,volatile 它所修饰的变量不保留拷贝,直接访问主内存中的.    在Java内存模型中,有main memory,每个线程也有自己的memory (例如寄存器).为了性能,一个线程会在自己 ...

随机推荐

  1. hdu 6047

    题解:先对b排序,用一个数组预处理a,记录当前位置之后到n的最大值,然后在用一个变量维护新增变量的最大值,用的时候和前面的数组的最大值做一个比较就ok. AC代码: #include <cstd ...

  2. C# 将一种类型的数组转化为另一种类型的数组

    //字符串数组(源数组) "}; //整型数组(目标数组) int[] iNums; //转换方法 iNums = Array.ConvertAll<string, int>(s ...

  3. JS经典算法

     寻找500以内能被5和7整除的数字:for(var num=1;num<=500&&num++;) if(num%7==0&&num%5==0){ consol ...

  4. 5.SpringMVC 配置式开发-处理器适配器

    处理器适配器HandlerAdapter 1.SimpleControllerHandlerAdapter(默认) 所有实现了 Controller 接口的处理器 Bean,均是通过SimpleCon ...

  5. tensorflow模型的保存与恢复,以及ckpt到pb的转化

    转自 https://www.cnblogs.com/zerotoinfinity/p/10242849.html 一.模型的保存 使用tensorflow训练模型的过程中,需要适时对模型进行保存,以 ...

  6. template.js 求和 问题

    基本适应方法在这不做叙述 <table> <tr> <th>值</th> <th>值</th> <th>值</ ...

  7. 解决安卓app在真机上的无法登录问题

    和小伙伴用安卓做的app在模拟器上可以正常使用,但是变成apk发到手机上下载使用时,出现无法的登录问题,而且登录提示的错误出现一秒就消失了,无法看清. 于是找了一下老师帮忙,老师是通过在电脑主机上插入 ...

  8. 《Redis 设计与实现》读书笔记(四)

    独立功能的实现 十八.发布和订阅 发布和订阅由下面几条命令组成 PUBLISH,发布消息,例如PUBLISH SUBSCRIBE,订阅某个频道 SUBSCRIBE UNSUBSCRIBE 退订某个频道 ...

  9. C# StmpClient使用 网络(四)

    发送邮件 //SmtpClient client = new SmtpClient("smtp.qq.com"); //client.EnableSsl = true; //cli ...

  10. SQL Server查询表结构语句

    --1:获取当前数据库中的所有用户表   www.2cto.com   select Name from sysobjects where xtype='u' and status>=0  -- ...