• 一、单例模式


    设计模式

    一、单例模式

    特点:

    1. 单例类只能有一个实例

    2. 单例类必须自己创建自己的唯一实例

    3. 单例类必须给所有其他对象提供这一实例

    解决问题:

    1. 一个全局使用的类频繁地创建与销毁

    1. 懒汉模式

    public class SingletonOne {
        private SingletonOne() {}
        private static SingletonOne instance = null;
        public static SingletonOne getInstance() {
            // 此处存在线程安全
            if (instance == null) {    
                instance = new SingletonOne();
            }
            return instance;
        }
    }

    2. 饿汉模式

    public class Singleton2 {
        private Singleton2() {}
        private static Singleton2 instance = new Singleton2();  // 类加载较慢
        public static Singleton2 getInstance() {
            return Singleton2.instance;
        }
    }

    3. 双重检查模式 (DCL)

    public class Singleton3 {
        private Singleton3() {}
        private static Singleton3 instance = null;
        public static Singleton3 getInstance() {
            if (null == instance) {
                // JVM编译器的指令重排 导致 线程安全
                synchronized (Singleton3.class) {
                    if (instance== null) {
                        instance= new Singleton3();
                    }
                }
            }
            return instance;
        }
    }

    4. 双重检查模式 - 优化版

    public class Singleton4 {
        private Singleton4() {}
        // volatile 关键字 禁止指令重排序
        private volatile static Singleton4 instance = null;
        public static Singleton4 getInstance() {
            if (null == instance) {
                synchronized (Singleton4.class) {
                    if (instance== null) {
                        instance= new Singleton4();
                    }
                }
            }
            return instance;
        }
    }

    5. 静态内部类

    /**
     * 1.从外部无法访问静态内部类LazyHolder,只有当调用Singleton.getInstance方法的时候,才能得到单例对象INSTANCE。
     * 2.INSTANCE对象初始化的时机并不是在单例类Singleton被加载的时候,而是在调用getInstance方法,使得静态内部类LazyHolder被加载的时候。
     *   因此这种实现方式是利用classloader的加载机制来实现懒加载,并保证构建单例的线程安全。
     */
    public class Singleton5 {
        private Singleton5() {}
        private static class LazyHolder {
            private static final Singleton5 INSTANCE = new Singleton5();
        }
        public static Singleton5 getInstance() {
            return LazyHolder.INSTANCE;
        }
    }

    5.1 反射打破单例模式的约束

    //获得构造器
    Constructor con = Singleton5.class.getDeclaredConstructor();
    //设置为可访问
    con.setAccessible(true);
    //构造两个不同的对象
    Singleton5 singleton1 = (Singleton5)con.newInstance();
    Singleton5 singleton2 = (Singleton5)con.newInstance();
    //验证是否是不同对象
    System.out.println(singleton1);
    System.out.println(singleton2);
    ​
    // 结果
    singleton.Singleton5@4554617c
    singleton.Singleton5@74a14482

    6. 枚举

    // 防止利用反射强行构建单例对象
    public enum Singleton6 {
        INSTANCE;
        public void doSomething(){
        }
    }

    7. 总结

    实现线程安全懒加载防止反射构建
    懒汉模式
    饿汉模式
    双重检查模式
    静态内部类
    枚举

    注意:一般情况下,不建议使用第 1 种和第 2 种懒汉方式,建议使用第 4 种饿汉方式。只有在要明确实现 lazy loading 效果时,才会使用第 5 种静态内部类方式。如果涉及到反序列化创建对象时,可以尝试使用第 6 种枚举方式。

    8. 补充

    1. volatile关键字不但可以防止指令重排,也可以保证线程访问的变量值是主内存中的最新值。有关volatile的详细原理,我在以后的漫画中会专门讲解。

    1. 使用枚举实现的单例模式,不但可以防止利用反射强行构建单例对象,而且可以在枚举类对象被反序列化的时候,保证反序列的返回结果是同一对象。

    1. 对于其他方式实现的单例模式,如果既想要做到可序列化,又想要反序列化为同一对象,则必须实现readResolve方法。

  • 相关阅读:
    deep_learning_Function_tensorflow_reshape()
    deep_learning_tensorflow_get_variable()
    deep_learning_Function_tensorflow_random_normal_initializer
    deep_learning_Function_numpy_newaxis参数
    deep_learning_Function_tensorflow_unpack()
    deep_learning_Function_tensorflow_transpose()
    deep_learning_LSTM长短期记忆神经网络处理Mnist数据集
    deep_learning_Function_rnn_cell.BasicLSTMCell
    嵌入式技术基础与实践-学习札记(一)
    2019-ACM-ICPC-徐州站网络赛- I. query-二维偏序+树状数组
  • 原文地址:https://www.cnblogs.com/Ddsl/p/13164203.html
Copyright © 2020-2023  润新知