zoukankan      html  css  js  c++  java
  • 单例模式DCL问题

      我们都知道在程序执行过程中,java虚拟机为了速率,有可能会产生重排序。拿最普通的初始化一个实例来讲。他的过程如下:

      (1)分配内存;

      (2)初始化实例;

      (3)将实例指向该内存。

      但是由于重排序的特性,可能最终的执行方式是1->3->2。如此就会产生,还没有将实例中的变量初始化完毕,就已经分配了内存。此时该实例已经不为null,但是其中的成员变量,还没有初始化为指定值。当别的线程调用时,就会返回错误的结果。

    举个例子:

    一般情况下,我们写一个单例模式可能会使用这种双重检查的方式;

    public class SingleClass{
        String a;
        String b;
        private static SingleClass instance;
        private SingleClass(){
            this.a = 1;---------------------------------5
            this.b = 2;---------------------------------6
        }
        public static SingleClass newInstance(){
            if(instance==null){-------------------------1
               synchronized(SingleClass.class){---------2
                    if(instance==null){-----------------3
                        instance = new instance();------4
                    }
               }
            }
            return instance;
        }    
    }

    但是当并发量高时,可能会出现上面那种情况,即线程A检查到1,但是重排序了,先将实例指向了内存地址,所以instance不再为null,他内部还没有初始化完毕,比如只初始化了a;此时线程B也调用了newInstance方法,检查到instance不为null,于是直接返回。此时返回的就是一个没有初始化b值的实例。造成数据缺失。

    因此我们可以使用共享变量volatile来修饰该实例的引用。

    对于volatile修饰的变量来说,禁止重排序,保障运行过程中写操作在读操作之前,如此就可以保障(1)-->(2)-->(3)的顺序,所以也不会产生上述情况了。

        private static volatile SingleClass instance;

    当然我们还推荐另一种方式,使用内部类的方法进行单例构造,可以从虚拟机层面保障单例啦;

    静态内部类的优点是:外部类加载时并不需要立即加载内部类,内部类不被加载则不初始化instance,因此不占内存。

    按照本例就是:当SingleInner第一次被加载时,并不需要去加载SingleHolder。只有当newInstance()方法第一次被调用时,才会去初始化instance,实现了惰性单例加载。

    public class SingleInner{
        String a;
        String b;
        private SingleInner(){
            this.a = 1;
            this.b = 2;
        }
        private static class SingleHolder{
            private static final SingleInner instance = new Instance();
        }
        public static SingleInner newInstance(){
            return SingleHolder.instance;
        }
    }
  • 相关阅读:
    特征归一化
    什么是端到端(end2end)学习?
    RSA加密原理及其证明
    python脚本中__all__变量的用法
    洛谷 1108 低价购买
    洛谷 3029 [USACO11NOV]牛的阵容Cow Lineup
    洛谷 1365 WJMZBMR打osu! / Easy
    洛谷 2759 奇怪的函数
    洛谷 2921 [USACO08DEC]在农场万圣节Trick or Treat on the Farm
    牛客网NOIP赛前集训营 提高组 第5场 T2 旅游
  • 原文地址:https://www.cnblogs.com/hekiraku/p/12192429.html
Copyright © 2011-2022 走看看