单例模式之我见

Posted Fable说

tags:

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

面试了十来个,问了单例没有一个满意的答案,尝试着写篇文章总结下。


单例模式在SDK开发中,非常重要,单例的目的:确保只有单个对象被创建;SDK唯一创建可以避免非常多的问题。示例代码,以java来写。


1.饿汉式

```java

public class Singleton {

   //创建 Main 的一个对象

   private static final Singleton instance = new Singleton();

   //让构造函数为 private,这样该类就不会被实例化

   private Singleton(){}

   //获取唯一可用的对象

   public static Singleton getInstance(){

      return instance;

   }

}

```


饿汉式关键点:

1)实例化对象,

2)构造函数声明为private,

3)获取这个类的对象,通过getInstance。


优点:

线程安全;实现简单。

缺点:

还没使用这个对象就创建了对象,浪费了资源。


2.懒汉式

```java

public class Singleton {  

    private static Singleton instance;  

    private Singleton (){}  

    public static synchronized Singleton getInstance() {  

    if (instance == null) {  

        instance = new Singleton();  

    }  

    return instance;  

    }  

}

```

懒汉式,关键点:

1)当需要当时候才初始化;

2)synchronized是为了防止多线程调用时,线程不一致而加的;不加会出问题

优点:

线程安全。

缺点:

锁的粒度是一整块代码,粒度偏大。


3.双重校验锁 DCL,即 double-checked locking

```java

public class Singleton {  

    private volatile static Singleton singleton;  

    private Singleton (){}  

    public static Singleton getSingleton() {  

    if (singleton == null) {  

        synchronized (Singleton.class) {  

            if (singleton == null) {  

                singleton = new Singleton();  

            }  

        }  

    }  

    return singleton;  

    }  

}

```

双重校验锁关键点:

1)if (singleton == null)判断了2次;如果第1次不写,多线程调用时,第2个线程调用时,还需要加锁一次,效率不高。

2)如果第2次不写,多线程调用时,会存在懒汉式一样的问题,线程不一致的问题


扩展:美团经典之问,DCL是否要加volatile?

volatile必须加,不加,指定重排,当对象有非初始化值时,如果发生了指令重排,这个对象的值是,初始值。

这个没法验证,当百万级高并发,会出现这个情况,而且你不知道问题出在哪。


优点:

线程安全。

缺点:

一不小心就踩坑。


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

关于单例模式的线程安全问题讨论以及加锁时机之我的想法

Android开发中常见的设计模式——单例模式

设计模式简单工厂之我见

C#的单例模式[关闭]

没有全局/单例的反应模式

领域驱动设计之我见-实现模式