• 23种设计模式之单例模式


    单例模式

    单例模式分八种方式

    1)饿汉式(静态常量)
    2)饿汉式(静态代码块)
    3)懒汉式(线程不安全)
    4)懒汉式(线程安全,同步方法)
    5)懒汉式(线程安全,同步代码块)
    6)双重检查
    7)静态内部类
    8)枚举

    饿汉式(静态常量)

    public class SingletonTest01 {
        public static void main(String[] args) {
    
            // 测试
            Singleton s1 = Singleton.getInstance();
            Singleton s2 = Singleton.getInstance();
    
            System.out.println(s1 == s2); // true
        }
    }
    
    /**
     * 饿汉式(静态变量)
     * */
    class Singleton {
    
        /**
         * 构造函数私有化,外部不能new
         * @param []
         * @date 2019/7/28 9:50
         **/
        private Singleton() {
    
        }
    
        /**
         * 本类内部创建实例对象
         * */
        private final static Singleton instance = new Singleton();
    
        /**
         * 对外提供接口获取对象
         * @param []
         * @date 2019/7/28 9:51
         * @return Singleton
         **/
        public static Singleton getInstance() {
            return instance;
        }
    
    }
    

      优缺点说明:
    1)优点:这种写法比较简单,就是在类加载的时候就完成实例化。避免了线程同步问题。
    2)缺点:在类加载的时候就完成实例化,没有达到Lazy Loading(懒加载)的效果。如果从始至终从未使用过这个实例,则会造成内存的浪费。
    3)结论:这种方式可用可能造成内存浪费。

    饿汉式(静态代码块)

    public class SingletonTest02 {
        public static void main(String[] args) {
            // 测试
            Singleton singleton1 = Singleton.getInstance();
            Singleton singleton2 = Singleton.getInstance();
    
            System.out.println(singleton1 == singleton2); // true
        }
    }
    
    /**
     * 饿汉式(静态代码块)
     * */
    class Singleton {
    
        /**
         * 构造函数私有化,外部不能new
         * @param []
         * @date 2019/7/28 9:50
         **/
        private Singleton() {
    
        }
    
        /**
         * 本类内部创建实例对象
         * */
        private static Singleton instance;
    
        /**
         * 在静态代码块中实例化对象
         * */
        static {
            instance = new Singleton();
        }
    
        /**
         * 对外提供接口获取对象
         * @param []
         * @date 2019/7/28 9:51
         * @return Singleton
         **/
        public static Singleton getInstance() {
            return instance;
        }
    }
    

      优缺点:
    1)这种方式和上面的方式类似的,优缺点一致。
    2)结论:这种方式可用,但可能会造成内存浪费。

    懒汉式(线程不安全)

    public class SingletonTest03 {
        public static void main(String[] args) {
            // 测试
            Singleton singleton1 = Singleton.getInstance();
            Singleton singleton2 = Singleton.getInstance();
    
            System.out.println(singleton1 == singleton2); // true
        }
    }
    
    /**
     * 懒汉式(线程不安全)
     * */
    class Singleton {
    
        /**
         * 创建未初始化的对象
         * */
        private static Singleton instance;
    
        /**
         * 构造函数私有化
         * */
        private Singleton() {
    
        }
    
        /**
         * 对外提供接口并实例化对象
         * 当使用该方法时,才实例化对象
         * */
        public static Singleton getInstance() {
            if (instance == null) {
                instance = new Singleton();
            }
            return instance;
        }
    
    }
    

      优缺点:
    1)起到了Lazy Loading的效果,但是只能在单线程的环境下使用。
    2)如果在多线程下,一个线程进入if(singleton == null)判断语句块,还未来得及往下执行,另一个线程也通过了判断语句,这是就会造成多实例现象。
    3)结论:在实际开发中,不可使用。

    懒汉式(同步方法,线程安全)

    public class SingletonTest04 {
        public static void main(String[] args) {
            // 测试
            Singleton s1 = Singleton.getInstance();
            Singleton s2 = Singleton.getInstance();
    
            System.out.println(s1 == s2);
        }
    }
    
    /**
     * 懒汉式(同步方法,线程安全)
     * */
    class Singleton {
    
        /**
         * 创建未实例化对象
         * */
        private static Singleton instance;
    
        /**
         * 构造函数私有化
         * */
        private Singleton(){}
    
        /**
         * 在同步锁下,进行判断实例化对象
         * @param []
         * @date 2019/7/28 10:33
         * @return Singleton
         **/
        public static synchronized Singleton getInstance() {
            if (instance == null) {
                instance = new Singleton();
            }
    
            return instance;
        }
    
    }
    

      优缺点:
    1)解决了线程不安全问题。
    2)效率太低,每个线程在想获取实例时,执行getInstance()方法都要进行同步。而其实这个方法只要执行一次就行,后面想获取该类实例,直接return就行了。
    3)结论:在实际开发中,不可用。

    懒汉式(同步代码块,线程不安全)

    public class SingletonTest05 {
        public static void main(String[] args) {
            // 测试
            Singleton s1 = Singleton.getInstance();
            Singleton s2 = Singleton.getInstance();
    
            System.out.println(s1 == s2);
        }
    }
    
    /**
     * 懒汉式(同步代码块,线程不安全)
     * */
    class Singleton {
    
        private static Singleton instance;
    
        private Singleton() {}
    
        public static Singleton getInstance() {
            if (instance == null) {
                synchronized(Singleton.class) {
                    instance = new Singleton();
                }
            }
    
            return instance;
        }
    }
    

      优缺点:
    1)这种方式本意是为了解决第四种方式效率低的问题。
    2)但是这种同步并不能起到线程同步的作用,和第三种方式遇到的情况类似。
    3)结论:在实际开发中,不可使用。

    双重检验

    public class SingletonTest06 {
        public static void main(String[] args) {
            // 校验
            Singleton s1 = Singleton.getInstance();
            Singleton s2 = Singleton.getInstance();
    
            System.out.println(s1 == s2); // true
        }
    }
    
    /**
     * 双重校验
     * */
    class Singleton {
    
        /** 创建未实例化对象 */
        private static volatile Singleton instance;
    
        /** 构造函数私有化 */
        private Singleton() {}
    
        /**
         * 进行双重校验,解决线程安全问题,同时解决懒加载问题,并且解决了效率问题
         * @param []
         * @date 2019/7/28 10:55
         * @return Singleton
         **/
        public static Singleton getInstance() {
            if (instance == null) {
                synchronized (Singleton.class) {
                    if (instance == null) {
                        instance = new Singleton();
                    }
                }
            }
    
            return instance;
        }
    }
    

      优缺点:
    1)Double-Check概念是多线程开发中经常使用的方式,如代码中所示,通过两重if(instance == null)检查,保证了线程安全。
    2)这样,实例化代码只要执行一次,后面再次访问就直接返回实例化对象,避免了重复的进行方法同步。
    3)线程安全,延迟加载,效率较高。
    4)结论:在实际开发中,推荐使用。

    静态内部类

    public class SingletonTest07 {
        public static void main(String[] args) {
            // 测试
            Singleton s1 = Singleton.getInstance();
            Singleton s2 = Singleton.getInstance();
    
            System.out.println(s1 == s2); // true
        }
    }
    
    /**
     * 静态内部类
     * */
    class Singleton {
    
        /**
         * 构造函数私有化
         * */
        private Singleton() {}
    
        /**
         * 静态内部类,该类中实例化Singleton属性
         * */
        private static class SingletonInstance {
            private final static Singleton INSTANCE = new Singleton();
        }
    
        /**
         * 对外提供接口获取实例化对象
         * */
        public static Singleton getInstance() {
            return SingletonInstance.INSTANCE;
        }
    
    }
    

      优缺点:
    1)这种方式利用类装载机制保证了在初始化实例时只有一个线程。
    2)静态内部类方式在Singleton类被装载时不会立即实例化,而是在需要实例化时,调用getInstance()方法,才会装载SingletonInstance类,从而完成了Singleton的实例化。
    3)类的静态属性只会在第一次加载类时初始化,所以在这里,JVM帮助我们保证了线程安全。
    4)优点:避免了线程不安全,利用静态内部类特点实现了延迟加载,并且效率较高。
    5)结论:在实际开发中,推荐使用。

    枚举

    public class SingletonTest08 {
        public static void main(String[] args) {
            Singleton s1 = Singleton.INSTANCE;
            Singleton s2 = Singleton.INSTANCE;
    
            System.out.println(s1 == s2); // true
            s1.sayOk();
        }
    }
    
    /**
     * 枚举
     * */
    enum Singleton {
        /**
         * 属性
         * */
        INSTANCE;
        public void sayOk() {
            System.out.println("ok");
        }
    }
    

      优缺点:
    1)通过枚举方式实现的单例模式。不仅可以避免多线程问题,而且还能防止反序列化重新创建对象。
    2)这种方式也是Effective Java作者提倡的方式。
    3)结论:推荐使用。

    注意事项和细节说明

    1)单例模式保证了系统内存中该类只存在一个对象,节省了系统资源,对于一些频繁创建销毁对象,使用单例模式可以提高系统性能。
    2)单例模式使用场景:需要频繁的进行创建和销毁对象、创建对象时耗时过多或耗费资源过多(即重量级对象),但又经常使用的、工具类对象、频繁访问数据库或文件的对象(数据源、session工厂)。

    总结:在使用单例模式时,考虑的问题无非就是线程是否安全、是否延迟加载、效率是否高等问题。当线程安全、延迟加载、效率较高时,该方式的单例模式就可用。

  • 相关阅读:
    convert image to base64 and post to RESTful wcf
    在android webview实现截屏的手动tounchmove裁剪图片
    How to use jquery ajax and android request security RESTful WCF
    using swfUpload in asp.net mvc
    using HttpClient and sending json data to RESTful server in adroind
    ODP.NET数据访问
    android image watermark
    解决国内不能访问github的问题
    idapro权威指南第二版阅读笔记第九章 交叉引用和绘图功能
    idapro权威指南第二版阅读笔记第二章 逆向和反汇编工具
  • 原文地址:https://www.cnblogs.com/dx520/p/11259010.html
Copyright © 2020-2023  润新知