Java并发编程——volatile关键字

 更新时间:2020年10月09日 10:48:58   作者:莫斐铭  
这篇文章主要介绍了Java并发编程——volatile关键字的相关资料,帮助大家更好的理解和学习Java并发编程,感兴趣的朋友可以了解下

一、volatile是什么

volatile是Java并发编程中重要的一个关键字,被比喻为“轻量级的synchronized”,与synchronized不同的是,volatile只能修饰变量,无法修饰方法及代码块等。
下面是使用volatile关键字实现的单例模式:

public class Singleton implements Serializable {
  private static volatile Singleton singleton;
  private Singleton() {}
  public static Singleton getSingleton() {
    if (singleton==null) {         // 1
      synchronized (Singleton.class) {  // 2
        if (singleton==null) {     // 3
          singleton = new Singleton();// 4
        }
      }
    }
    return singleton;
  }
  private Object readResolve() { //防止序列化破坏单例模式
    return singleton;
  }
}

1.单例为什么使用volatile关键字?

首先要理解new Singleton()做了什么。1.看class对象是否加载,如果没有就进行类的加载、解析和初始化;2.虚拟机分配内存空间,初始化实例,3.调用构造函数,4.返回地址给引用。而cpu为了优化程序,可能会进行指令重排序,导致实例内存还没分配,就被使用了。

假设有两个线程A和B,线程A执行到new Singleton(),开始初始化实例对象,由于存在指令重排序,这次new操作,先把引用赋值了,还没有执行构造函数(没有真正执行完)。这时时间片结束了,切换到线程B执行,线程B调用new Singleton()方法,发现引用不等于null,就直接返回引用地址了,然后线程B执行了一些操作,就可能导致线程B使用了还没被初始化的变量。

2.单例模式中步骤1、2、3、4存在的意义何在?

首先,步骤2、3是保证单例。假设线程A和B都执行到了步骤2,线程A拿到了锁,执行步骤3,如果此时没有创建实例,线程A会执行new创建实例,然后线程A释放锁,线程B拿到锁,首先执行步骤3,发现已经创建了实例,直接返回。加锁是比较消耗资源的,步骤1就是为了减少资源的消耗。

二、volatile的特性

1.禁止指令重排序

指令重排序是JVM为了优化指令、提高程序运行效率,在不影响单线程程序执行结果的前提下,尽可能地提高并行度。指令重排序包括编译器重排序和运行时重排序。

volatile关键字提供内存屏障的方式来防止指令被重排,编译器在生成字节码文件时,会在指令序列中插入内存屏障来禁止特定类型的处理器重排序。

JVM内存屏障插入策略:

  • 每个volatile写操作的前面插入一个StoreStore屏障,Store1;StoreStore;Store2,在Store2及后续的写入操作执行前,保证Store1的写入操作对其他处理器可见,保证了有序性和可见性;
  • 在每个volatile写操作的后面插入一个StoreLoad屏障,Store1;StoreLoad;Load2,在Load2及后续的读取操作执行前,保证Store1的写入操作对其他处理器可见,它的开销是最大的,兼具其他三种的作用,保证了有序性和可见性;
  • 在每个volatile读操作的后面插入一个LoadLoad屏障,Load1;LoadLoad;Load2,在Load2及后续的读取操作执行前,保证Load1读取的数据已经读取完毕;
  • 在每个volatile读操作的后面插入一个LoadStore屏障,Load1;LoadStore;Store2,在Store2及后续的写入操作执行前,保证Load1读取的数据已经读取完毕。

2.保证内存可见性

可见性是指对volatile变量的读总能获取其他任意线程对volatile变量的最后的写。
可见性的实现基于volatile读写的内存语义:

  • volatile写的内存语义:当写入一个volatile变量时,JVM将线程工作内存中的变量值刷新到主内存中;
  • volatile读的内存语义:当读取一个volatile变量时,JVM首先将改工作内存中的变量设置为无效,重新从主内存中获取最新的有效值。

三、使用场景

(1)volatile是轻量级同步机制。与synchronized的区别是volatile只能保证有序性和可见性,不能保证原子性。
(2)volatile不能修饰写入操作依赖当前值的变量。声明为volatile的简单变量如果当前值与该变量以前的值相关,那么volatile关键字不起作用,也就是说如下的表达式都不是原子操作:“count++”、“count = count+1”。
(3)当要访问的变量已在synchronized代码块中,或为常量时,没必要使用volatile;
(4)volatile保证了有序性,屏蔽掉了JVM中必要的代码优化,所以在效率上比较低,因此一定在必要时才使用此关键字。
(5)在以下两个场景中可以使用volatile来代替synchronized:

  • 运算结果不依赖变量的当前值,或者能够确保只有单一的线程会修改变量的值。
  • 变量不需要与其他状态变量共同参与不变约束。

以上就是浅析Java并发编程——volatile关键字的详细内容,更多关于Java并发编程——volatile关键字的资料请关注脚本之家其它相关文章!

相关文章

  • 详解为什么阿里巴巴禁止使用BigDecimal的equals方法做等值比较

    详解为什么阿里巴巴禁止使用BigDecimal的equals方法做等值比较

    这篇文章主要介绍了详解为什么阿里巴巴禁止使用BigDecimal的equals方法做等值比较,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • SpringBoot实现单元测试示例详解

    SpringBoot实现单元测试示例详解

    单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。这篇文章主要为大家介绍了C语言实现单元测试的方法,需要的可以参考一下
    2022-11-11
  • java8 集合求差集、并集、交集的实例

    java8 集合求差集、并集、交集的实例

    下面小编就为大家分享一篇java8 集合求差集、并集、交集的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2017-12-12
  • 利用AOP实现系统告警的方法详解

    利用AOP实现系统告警的方法详解

    在开发的过程中会遇到各种各样的开发问题,服务器宕机、网络抖动、代码本身的bug等等。针对代码的bug,我们可以提前预支,通过发送告警信息来警示我们去干预,尽早处理。本文将利用AOP实现系统告警,需要的可以参考一下
    2022-09-09
  • Mybatis 插入和删除批处理操作

    Mybatis 插入和删除批处理操作

    在操作数据库时,经常会碰到批量插入、批量删除的情况,直接执行SQL语句还好做一点,当使用Mybatis进行批量插入、批量删除时会有一些问题。下面对使用Mybatis批量插入,批量删除进行介绍
    2016-12-12
  • Springboot的yml配置文件用法

    Springboot的yml配置文件用法

    这篇文章主要介绍了Springboot的yml配置文件用法,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03
  • SpringBoot热部署设置方法详解

    SpringBoot热部署设置方法详解

    在实际开发中,每次修改代码就需要重启项目,重新部署,对于一个后端开发者来说,重启确实很难受。在java开发领域,热部署一直是一个难以解决的问题,目前java虚拟机只能实现方法体的热部署,对于整个类的结构修改,仍然需要重启项目
    2022-10-10
  • Java实现大文件的分割与合并的方法详解

    Java实现大文件的分割与合并的方法详解

    这篇文章主要为大家详细介绍了如何利用Java语言实现大文件的分割与合并,以及分割后又再次合并操作,文中示例代码讲解详细,感兴趣的可以了解一下
    2022-08-08
  • SpringBoot实现在webapp下直接访问html,jsp

    SpringBoot实现在webapp下直接访问html,jsp

    这篇文章主要介绍了SpringBoot实现在webapp下直接访问html,jsp问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-10-10
  • Java基础高级综合练习题扑克牌的创建

    Java基础高级综合练习题扑克牌的创建

    今天小编就为大家分享一篇关于Java基础高级综合练习题扑克牌的创建,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-01-01

最新评论