单例模式

Singleton pattern

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

饿汉模式

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

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<String, Object> objMap = new HashMap<String,Object>();
  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) ;
  }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

友情链接更多精彩内容