单例模式

Posted jerrice

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单例模式相关的知识,希望对你有一定的参考价值。

转自: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 

 

以上是关于单例模式的主要内容,如果未能解决你的问题,请参考以下文章

常用代码片段

性能比较好的单例写法

片段作为 Android 中的单例

单例片段或保存网页视图状态

你熟悉的设计模式都有哪些?写出单例模式的实现代码

单例模式以及静态代码块