• 单例模式


    转自:https://my.oschina.net/pingpangkuangmo/blog/376329

    一个类只能构造一个对象。

    分为懒汉式和饿汉式

    饿汉式:

    public final class Singleton {
    
        private static final Singleton instance=new Singleton();声明时就已构造出对象
        
        private Singleton(){}
        
        public static Singleton getInstance(){
            return instance;
        }
    }

    简单粗暴,线程安全。

    特点:1.构造器私有,使得别人无法再创建新对象(通过反射方式除外)。

    2.提供一个静态方法用于获取对象实例。在类加载器加载Singleton的时候就会去初始化创建一个Singleton实例,类加载器加载Singleton时线程安全的

    懒汉式:延迟初始化

    public final class Singleton {
    
        private volatile static Singleton instance=null;//加volatile 禁止重排序
        
        private Singleton(){}
        
        public static  Singleton getInstance(){
            if(instance==null){                 //第一个if,先判断是否为null,减小开销。因为不管有没有初始化都执行sychronized同步,开销很大
                synchronized (Singleton.class) {
                    if(instance==null){          //第二个if, 有可能此时已经初始化了,所以要再次判断
                        instance=new Singleton();
                    }
                }
            }
            return instance;
        }
    }

    双重检查机制。看似已经完美,实则不然。instance=new Singleton()实际上分为三个过程: 
    1 分配内存 
    2 对Singleton的一些初始化工作包括构造函数的执行 
    3 对instance变量赋值内存地址 

    不同的编译器优化时,2和3之间可能会重排序,导致结果:线程1当执行到第2步的时候,instance就已经有值了,此时线程2执行getInstance方法的最外层的if(instance==null)判断就会直接返回。然而该对象还没有真正的完成初始化,还不能正常使用。此时线程2如果去使用该对象,就会出问题了。

    具体过程可见:https://my.oschina.net/pingpangkuangmo/blog/376329,一目了然

    另一种解决方案:依靠jvm对类和接口的同步来实现单例线程安全的

    public final class Singleton {
    
        private static class SingletonHolder{
            public static Singleton instance=new Singleton();
        }
        
        private Singleton(){}
        
        public static  Singleton getInstance(){
            return SingletonHolder.instance;
        }
    }

    当多个线程执行SingletonHolder.instance时,会首先进行类的初始化,即多个线程可能同时去初始化同一个类,这方面对于jvm来说是进行了细致的同步,每个类都有一个初始化锁,来确保只能有一个线程来初始化类。当线程A获取了SingletonHolder类的初始化锁,线程B则需要等待,线程A就要去执行SingletonHolder的静态变量表达式、静态代码块等初始化工作,然后就能确保Singleton instance=new Singleton()只被一个线程来执行。 
    总的来说,此种方法是依靠jvm对类和接口的同步来实现单例线程安全的。具体jvm对于类和接口初始化的同步过程可以见这篇文章http://www.infoq.com/cn/articles/double-checked-locking-with-delay-initialization 

  • 相关阅读:
    关于最大最小的k个数的类型题总结
    最小的K个数(剑指offer)
    215. Kth Largest Element in an Array(返回数组中第几大元素)(leetcode)
    数组中出现次数超过一半的数字(剑指offer)
    二叉搜索树与双向链表(剑指offer)
    第四届蓝桥杯c/c++B组6
    第四届蓝桥杯c/c++B组7
    第四届蓝桥杯c/c++B组8
    第四届蓝桥杯c/c++B组9
    第五届蓝桥杯 c/c++ B组8
  • 原文地址:https://www.cnblogs.com/jerrice/p/7390803.html
Copyright © 2020-2023  润新知