volatile变量

关键字volatile是虚拟机提供的一种轻量级的同步机制,但在做多线程开发时,大部分的人都不太习惯喜欢用volatile,而是直接用关键字synchronized来进行同步。但有些时候在解决线程安全问题时,使用volatile关键字要比使用synchronized同步函数更好一些。下面我们详细分析一下在Java中关键字volatile到底是一个什么样的东东,底层是怎么实现的。

在JMM中虚拟机对volatile关键字专门定义了一些特殊的访问规则,来实现线程的轻量级同步。当变量是一个volatile变量时,它就会具有两种特殊的特性。

  • 第一个特性就是保证此变量对所有线程的可见性。可见性的意思是说当一个线程修改了volatile变量时,对于其它线程可以立即知道修改后的值。而普通变量则不具有此特性,普通变量只能通过主内存来完成。也就是说如果某一个线程修改了普通变量的值,只能向主内存同步后,其它线程在从主内存中拷贝后,才可以得到新的普通变量的值。虽然volatile变理具有可见性,但在使用volatile变量时,并不能保证不会出现线程安全问题。我们请看下面的代码。

按照代码的逻辑,每个线程都会调用1000次increase()方法,也就是每一个线程都会执行1000次volatile变量的自增。并且我们开启了10个线程,按照volatile变量可见性的分析,在正常情况下最后输出的值就应该是10000。但实际的结果却小于10000这是为什么呢?

问题的原因就是虽然volatile变量具有可见性,能够保证其它线程立即获取到更新后的值。但问题的原因却是自增运算导致的。也就是race++。在Java中自增运算并不是原子性的操作,所以在程序运行自增运算时,其它线程也有可能执行。我们使用javap命令来查看一下编译后的字节码就明白了其中的缘由了。

我们主要看increase()方法中的字节码即可。在字节码中使我们知道虽然在源码中我们只写了一条语句,但是在字节码执行时,是需要5条指令来实现自增运算的。虽然volatile变量可以保证在虚拟机执行字节码时变量是最新的值,但是并不能保证在执行其它指令时,别的线程不在更新volatile变量。如果在此线程没有执行自增运算指令时,其它线程已经对volatile变量进行了修改,那么在此线程在执行自增运算时,得到的volatile变量已经是过期的了,既然是过期的值,那就一定会比真正的值要小,于是此线程就把已经过期的volatile变量的值同步到了主内存中,所以程序在执行时,最后的执行结果会比预计执行的值要小。

使用volatile变量的别一种特性就是禁止指令重排序优化。重排序的意思是说CPU在执行指令时,为了进行优化处理,常常会对指令进行重新排序,也就是说CPU执行指令的顺序在重排序后是有可能和程序源码中的顺序是不一样的,但CPU并不会影响程序原有的运行结果。

本文分享自微信公众号 - 吉林乌拉(jilinwulacom)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-07-01

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Java中volatile关键字的使用

    volatile关键字的作用就是使变量在多个线程间可见。这到底是什么意思呢?我们先看下面的事例然后在详细说明。

    吉林乌拉
  • Executor的使用

    在上一篇我们简单的介绍了线程池的使用,虽然线程池比我们直接使用原始的线程类更加方便,但在创建线程池对象时对参数的设置是需要开发人员精心考量的,否则线程池并不会实...

    吉林乌拉
  • ThreadPoolExecutor的使用

    ThreadPoolExecutor也就是线程池。它就是Java为我们开发多线程程序时提供的一个开发框架。它可以统一的管理线程的创建、销毁、优化、监控等,在使用...

    吉林乌拉
  • ava多线程:volatile变量、happens-before关系及内存一致性

    请参考来自 Jean-philippe Bempel 的评论。他提到了一个真实因 JVM 优化导致死锁的例子。我尽可能多地写博客的原因之一是一旦自己理解错了,可...

    哲洛不闹
  • 深入理解Java多线程中的volatile关键字Java 的 volatile关键字对可见性的保证Java 的 volatile关键字在保证可见性之前的所做的事情Volatile有时候也是不够的什么时

    Java关键字用于将一个变量标记为“存储在内存中的变量”。更准确的说,意思就是每一次对volatile标记的变量进行读取的时候,都是直接从电脑的主内存进行的,而...

    desperate633
  • 深入分析Volatile的实现原理

    在多线程并发编程中synchronized和Volatile都扮演着重要的角色,Volatile是轻量级的synchronized,它在多处理器开发中保证了共享...

    heasy3
  • Java并发编程的艺术(三)——volatile

    1. 并发编程的两个关键问题 并发是让多个线程同时执行,若线程之间是独立的,那并发实现起来很简单,各自执行各自的就行;但往往多条线程之间需要共享数据,此时在并...

    大闲人柴毛毛
  • 内存可见性

    SuperHeroes
  • 你知道Java并发三大问题么,volatile和CAS又是什么?

    如果是在一个串行执行的语言中,执行SetCheck类中的check方法永远不会返回false,即使编译器,运行时和计算机硬件并没有按照你所期望的逻辑来处理这段程...

    Java技术江湖
  • 【死磕Java并发】—–深入分析volatile的实现原理

    通过前面一章我们了解了synchronized是一个重量级的锁,虽然JVM对它做了很多优化,而下面介绍的volatile则是轻量级的synchronized。如...

    用户1655470

扫码关注云+社区

领取腾讯云代金券