设计模式之01:单例模式

单例模式可以避免多个对象对资源的消耗。

使用场景

当某类只需一个对象的时候,如:IO的访问;数据库的访问;图片加载ImageLoader。

为什么ImageLoader要使用单例?
ImageLoader中又含有线程池、缓存、网络请求等比较耗资源的对象,如果多次构建,则会消耗过多资源。

实现方式

1. 声明式:不推荐
    private Test() {
    }

    public final static Test test = new Test();

优点:简单
缺点:粗暴(系统启动时初始化,对节约资源不够充分)

2. 懒汉式:不推荐
    private Test() {
    }

    private static Test test;

    public static synchronized Test getInstance() {
        if (test == null) {
            test = new Test();
        }
        return test;
    }

优点:第一次使用时候初始化,保证线程安全
缺点:每次使用都会同步,性能差

3. DCL(Double Check Lock)方式:可用,最常用的方式。
    private Test() {
    }

    private static Test test;

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

优点:第一次使用时初始化,保证线程安全,避免不必要的同步
缺点:高并发环境有缺陷

4. 静态内部类式:推荐。
    private Test() {
    }

    public static Test getInstance() {
        return InstanceHolder.test;
    }

    private static class InstanceHolder {
        private final static Test test = new Test();
    }

优点:延迟实例化,线程安全,单例唯一性。
缺点:class个数增加。

5. 枚举式
public enum Test {

    Instance;

    private int count;

    public void countPlus(int plus) {
        count += plus;
    }

}

使用:Test.Instance.countPlus(3);
优点:线程安全,绝对唯一性(上述的几种方式,在反序列化情况下会重新创建对象)。
缺点:没有延迟加载。

6. 容器式
    private static Map instanceMap = new HashMap<>();

    public static void registerService(String key, Object instance) {
        if (!instanceMap.containsKey(key)) {
            instanceMap.put(key, instance);
        }
    }

    public static Object getService(String key) {
        return instanceMap.get(key);
    }

系统启动时,将多种单例注入容器,使用时取出。

总结

单例的核心都是将构造函数私有化,通过静态方法获取唯一实例,尽量节约资源提高性能,保证线程安全,防止反序列化导致重新实例化。

你可能感兴趣的:(设计模式之01:单例模式)