zoukankan      html  css  js  c++  java
  • 单例模式的double check写法中的volatile关键字

    在多线程环境中,volatile能保证共享变量的可见性以及一定程度的有序性。单例模式有多种写法,有线程安全的和非线程安全的,有懒汉式和饿汉式,有利用static关键字修饰变量、方法、代码块、内部类的实现,还有用枚举实现的,今天我们讨论下单例模式里面较为复杂的double check写法,先看下代码:

     1 public class Singleton{
     2     private static volatile Singleton instance = null;
     3     
     4     private Singleton(){}
     5 
     6     public Singleton getInstance(){
     7         if(null == instance){
     8             synchronized(Singleton.class){
     9                 if(null == instance){
    10                     instance = new Singleton();
    11                 }
    12             }
    13         }
    14         return instance;
    15     }
    16 }
    1. 为什么需要两次check?
      1. 如果没有外层的check,相当于给整个getInstance()方法加上了synchronized关键字,也就是每次获取单例对象都要获取class对象的monitor,monitor是粒度较大的的锁,开销较大。所以外层的判断目的是:第一次获取单例对象后,再次获取该单例对象无需进行同步
      2. 如果没有内层的check,假如有两个线程,线程1和线程2同时进入外层判断,即第8步,线程1获得对象锁,进入同步代码块并初始化对象后,释放对象锁,返回单例对象结束了,线程1获取对象锁进入同步代码块后又再次初始化了instance对象,导致多线程下单例模式的非线程安全;
    2. 为什么instance实例需要加volatile关键字?
    3. 因为volatile的禁止指令重排序,在第10步中,初始化instance对象并非原子操作,它包括:1.开辟堆内存2.调用构造方法初始化对象3.将instance指向新对象;如果没有volatile关键字,且在并发情况下,如果某个线程完成了1 2两个步骤,还未给instance变量赋值,此时另一个线程进入外层判空后后发现instance对象非空,就返回了未构造完全的instance对象,导致空指针异常;volatile的意义在于能够禁止对当前对象进行指令的重排序,也就是happen-before原则的关于volatile的一条:"volatile变量规则:对一个变量的写操作happen before于后面对这个变量的读操作",也就是说,无论什么情况,对于volatile变量的写操作必须在完成后才能读取,不能暴露写操作的中间状态。所以不会出现未完成构造就读取的情况;但是volatile不能保证同时对变量的写操作也是有序的,也就是volatile不能保证原子性

    happen before:描述了线程安全的可见性,有很多规则,关于volatile的规则是:对一个变量的写操作的结果,对这个变量的读操作可见

    参考链接:

    1. https://www.cnblogs.com/dolphin0520/p/3920373.html
    2. https://stackoverflow.com/questions/7855700/why-is-volatile-used-in-this-example-of-double-checked-locking
    3. https://blog.csdn.net/DL88250/article/details/5439024
    4. https://www.cnblogs.com/dolphin0520/p/3613043.html
  • 相关阅读:
    致 CODING 用户的元宵问候
    持续集成之理论篇
    基于 CODING 的 Spring Boot 持续集成项目
    使用 CODING 进行 Hexo 项目的持续集成
    使用 CODING 进行 Spring Boot 项目的集成
    三种前端模块化规范
    XSS和CSRF
    小问题填坑,关于obj.x和obj["x"]
    说一个闭包在实际开发中的应用
    关于return的分号自动插入问题
  • 原文地址:https://www.cnblogs.com/boboshenqi/p/9403627.html
Copyright © 2011-2022 走看看