单例模式

Singleton pattern

限定类对象只有一个实例
核心原理是将构造函数私有化,并且通过静态方法获取一个唯一的实例,在这个过程中保证线程安全。

饿汉模式

实例在类加载初始化的时候就由函数创建

public final class Singleton {
    private static final Singleton INSTANCE = new Singleton();

    private Singleton() {}

    public static Singleton getInstance() {
        return INSTANCE;
    }
}

缺点:饿汉模式初始化的过早,如果仅仅调用了单例类的静态函数,也会进行初始化


懒汉模式

延迟加载:在使用时才初始化,效率高,第一次加载反应稍慢
通过 double-checked locking 双重检查锁定,实现线程安全

public final class Singleton {
    private static volatile Singleton instance = null;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized(Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

volatile的作用:保证变量可见性和禁止指令重新排序
在这里主要是避免指令重排,否则Singleton实例分配对象后,可能直接将instance指向对应的内存空间,而构造函数还在初始化成员字段,此时另一个线程就会直接使用尚未初始化完成的单例对象instance,可能产生错误


静态内部类

线程安全,延迟了实例化,只有在调用getInstance时才会实例化

public final class Singleton{
    private Singleton(){}
    public static Singleton getInstance(){
        return SingletonHolder.INSTANCE;
    }

    private static class SingletonHolder{
        private static final Singleton INSTANCE = new Singleton();
    }
}

静态内部类的加载不需要依附外部类,在使用时才加载。不过在加载静态内部类的过程中也会加载外部类


枚举单例

写法简单,通过Singleton.INSTANCE.getInstance()获取单例

class Resource{
}

public enum Singleton{
    INSTANCE;
    private Resource instance;
    Singleton() {
        instance = new Resource();
    }
    public Resource getInstance() {
        return instance;
    }
}
  • enum没有public的构造器,防止外部的额外构造,恰好和单例模式吻合
  • 用枚举实现单例,类似于饿汉模式,没有实现延迟实例化
  • 枚举的反序列化不会生产新的实例

容器类

将多种单例类型注入到一个统一管理的容器中,在使用时根据key获取对应类型的对象。这种方式可以管理多种类型的单例,使用统一的接口进行获取操作

public class SingletonManager { 
  private static Map objMap = new HashMap();
  private Singleton() { 
  }
  public static void registerService(String key, Objectinstance) {
    if (!objMap.containsKey(key) ) {
      objMap.put(key, instance) ;
    }
  }
  public static ObjectgetService(String key) {
    return objMap.get(key) ;
  }
}

你可能感兴趣的:(单例模式)