原文连接:(http://www.studyshare.cn/blog/details/1163/0 )

一、volatile定义

volatile是java并发编程中修饰类的成员变量、成员属性或者对象的一个关键字。是java并发编程中最轻量级的并发实现,保证所修饰的变量对多个线程内存可见。在一个线程写,多个线程读的场景下,首选使用volatile关键字。

java开发工具下载地址及安装教程大全,点这里
更多技术文章,在这里

二、使用案例

此处用一个线程安全的单例模式来说明volatile具体的使用场景和原理,首先,线程安全的单例模式是很多面试官都喜欢考察面试者的一个问题,网络上各种博客都谈到饿汉式,懒汉式单例模式的编写方式,也提到过一个双重检查模式的单例模式,双重检查单例模式代码如下:

相信很多人认为这已经是线程安全的单例模式了,然而这真的是线程安全的吗?其实不是,为什么呢?原因其实很简单,如果两个线程调用getInstance()方法的时候,其中某一个线程正在执行第一重检查,另外一个线程正在执行第二重检查中的instance = new Singlton()的时候,此时这句实例化的代码在我们看来只有一句,但翻译成cpu能运行的指令的时候会变成三句:(1)给instance分配一个栈指针,(2)给Singlton对象分配堆内存,(3)将栈指针指向堆内存。那么cpu在做这三步操作的时候执行顺序会重排序(cpu按自己的规则重新排序后执行),即执行顺序可能是(1)(3)(2),那么问题就来了,当执行(1)后,假如第一个线程正在执行第一重检查,那么此时会发现instance并不为空,就直接返回了。然而实际对象分配堆内存还没完成,此时就会造成instance只是一个空的指针。当我们调用Singlton对象中的成员变量时,就会出错。问题出来了,那么解决方法非常简单,就是使用该文章的主题--volatile关键字,在我们对象成员变量上加上volatile即可。

private static volatile Singlton instance ;

三、深入剖析

要理解透彻volatile的原理需要明白cpu指令重排序、内存屏障以及线程的本地缓存和主内存等相关知识。指令重排序:以上的示例也说明了cpu在执行一条我们编写的代码的时候,首先会编译成汇编语言,最终编译成二进制指令后在cpu的寄存器上进行存取并执行。即一条代码会变成n条指令,cpu执行这n条指令的时候,不会老老实实的按顺序进行执行,而是会按一定的规则(可能是先简单后复杂,
先加减后乘除等等)重新排序后执行。这就是指令重排序。重排序的类型有编译器优化重排序,指令级并行重排序,内存系统重排序。
内存屏障:这是针对并发下重排序带来的问题的一种解决方案,现代cpu都有的一种内存屏障类型是:StoreLoad Barriers,另外还有三种分别是:LoadLoad Barriers、StoreStore Barriers以及LoadStore Barriers.

线程的本地缓存与主内存:

(1)、每个线程都会有自己的本地缓存,如上图所示,线程A,线程B都会有自己的本地缓存,用来缓存线程本身所需要使用的数据。
(2)、正常情况下,当线程A改变了自己本地缓存中的a变量的值,并不会马上刷新到主内存,同理,线程B也一样。
(3)、如果给a变量加上volatile修饰,那么当线程A改变了本地缓存中a的值后,cpu会强制将线程A的本地缓存中的a变量的值刷新到主内存,即让主内存的a的值与线程A的本地缓存中的a值一致。且同时让线程B中的本地缓存中的a失效,那么当线程B要使用本地缓存中的a变量的时候,会重新到主内存读取并刷新自己的本地缓存。这就是volatile的内存语义。然后回头解释案例中为何加入volatile修饰就保证了真正的线程安全,直接来说就是一句话:volatile修饰的变量在cpu底层执行的时候插入了相关的内存屏障禁止指令进行重排序。具体来说是在volalite写操作前插入StoreStore屏障,写操作后面插入StoreLoad屏障,在volatile读操作的后面连续插入LoadLoad屏障和LoadStore屏障。
总结:volatile关键字修饰的变量具有内存可见性,对一个volatile变量的读,总是能看到(任意线程)对这个变量最后的写入。volatile的并发实现是利用cpu的lock前缀指令对消息总线进行加锁,同时让volatile当前所在线程的本地缓存内容强行刷进主内存,并让其他使用了该变量的本地缓存失效,当其他线程需要使用volatile所修饰的变量的时候就会重新到主内存中读取。
本文为博主原创文章,欢迎留言交流,转载请注明原文出处。
java开发工具下载地址及安装教程大全,点这里
更多技术文章,在这里

volatile-最轻量级的并发实现及其内存语义的更多相关文章

  1. Java并发编程原理与实战四十二:锁与volatile的内存语义

    锁与volatile的内存语义 1.锁的内存语义 2.volatile内存语义 3.synchronized内存语义 4.Lock与synchronized的区别 5.ReentrantLock源码实 ...

  2. 【java多线程系列】java中的volatile的内存语义

    在java的多线程编程中,synchronized和volatile都扮演着重要的 角色,volatile是轻量级的synchronized,它在多处理器开发中保证了共享变量的可见性,可见性指的是当一 ...

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

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

  4. JAVA锁和volatile的内存语义&volatile的使用场景

    JAVA锁的内存语义 当线程释放锁时,JMM(Java Memory Model)会把该线程对应的本地内存中的共享变量刷新到主内存中. 当线程获取锁时,JMM会将该线程对应的本地内存置为无效.从而使得 ...

  5. volatile 和锁的内存语义

    一.volatile 的内存语义 1. volatile 的特性 volatile变量自身具有以下特性: 可见性 :对一个volatile变量的读,总是能看到(任意线程)对这个volatile变量最后 ...

  6. volatile的内存语义与应用

    volatile的内存语义 volatile的特性 理解volatile特性的一个好方法是把对volatile变量的单个读/写,堪称是使用同一个锁对这些单个读/写操作做了同步. 锁的happens-b ...

  7. 基础篇:深入JMM内存模型解析volatile、synchronized的内存语义

    目录 1 java内存模型,JMM(JAVA Memory Model) 2 CPU高速缓存.MESI协议 3 指令重排序和内存屏障指令 4 happen-before原则 5 synchronize ...

  8. Java内存模型(MESI、内存屏障、volatile和锁及final内存语义)

    JMM (Java内存模型) Java线程的实现 实现线程主要有三种方式,Java线程从JDK1.3后采用第一种方式实现: 使用内核线程实现(1:1实现) 使用用户线程实现(1:N实现) 使用用户线程 ...

  9. volatile特性及内存语义

    1.volatile变量自身具有下列特性:·可见性:对一个volatile变量的读,总是能看到(任意线程)对这个volatile变量最后的写入.·原子性:对任意单个volatile变量的读/写具有原子 ...

随机推荐

  1. Redis Streams 介绍

    Stream是Redis 5.0版本引入的一个新的数据类型,它以更抽象的方式模拟日志数据结构,但日志仍然是完整的:就像一个日志文件,通常实现为以只附加模式打开的文件,Redis流主要是一个仅附加数据结 ...

  2. jQuery实现列表框双向选择操作

    对列表框的操作经常碰到过这样的应用:从左侧的列表框中选中要选的项添加到右侧列表框中,然后提交最终选择的项,对误操作而选中的项还可以执行移除操作.在很多系统中应用比如说求职网站的选择意向工作地区,QQ好 ...

  3. What is the difference between UNION and UNION ALL?

    What is the difference between UNION and UNION ALL? UNION removes duplicate records (where all colum ...

  4. Xamarin.FormsShell基础教程(5)Shell项目内容新建页面

    Xamarin.FormsShell基础教程(5)Shell项目内容新建页面 轻拍内容列表页面中的Add按钮后,进入内容新建页面,如图1.4和图1.5所示.在该页面中,用户可以设置新建内容的标题和具体 ...

  5. C#Selenium常用语法功能 很好的文章,值得参考收藏

     https://blog.csdn.net/a1003434346/article/details/80257946 https://www.jianshu.com/p/310623afcde1 h ...

  6. Eclipse4.2juno安装git

    因为项目需要,需要再Eclipse4.2juno上面安装git,试了几次都没有成功,网上搜了下,结合报错发现,Eclipse4.2juno支持的最高版本是git3.2,因此,选选择3.2版本的git安 ...

  7. Consider defining a bean of type 'com.*.*.mapper.*.*Mapper' in your configuration.

    @Mapper 不能加载的问题 Consider defining a bean of type 'com.*.*.mapper.*.*Mapper' in your configuration. 添 ...

  8. Difference Between Accuracy and Precision

    What Is the Difference Between Accuracy and Precision? https://www.thoughtco.com/difference-between- ...

  9. SVN中“txn-current-lock:拒绝访问”错误

    SVN服务器使用的是Visual SVN,重装系统后,使用SVN commit是遇到:不能打开文件“XX:\XXXXX\db\txn-current-lock”: 拒绝访问这样的错误. 原因分析: u ...

  10. django web问题

    django生命周期 1. 当用户在浏览器中输入url时,浏览器会生成请求头和请求体发给服务端 请求头和请求体中会包含浏览器的动作(action),这个动作通常为get或者post,体现在url之中. ...