设计模式——单例模式

  定义:

    保证一个类只有一个实例,并提供一个访问它的全局访问点。

  实现:

    1. 将构造方法私有化。外部不能通过构造方法来实例化一个对象,只能通过静态方法来获得该类的唯一实例。

    2. 定义一个私有类的静态变量。(静态方法不能访问非静态成员变量,所以定义一个静态变量)

    3. 提供一个共有的获取实例的静态方法。

 

  好处:

    单例模式的特点是单例类在应用程序中只被实例化一次,以保证外界访问的都是同一个对象。避免了多次创建的问题,节省系统资源,加快对象的访问速度。

  缺点:

    不适于变化的对象,没有抽象层不利于扩展。

 

  五种书写单例模式方式:

  1. 懒汉式    

    在第一次使用时候才进行初始化,有线程安全问题,达到懒加载效果。 添加关键字 synchronized 保证线程安全。防止多线程中A和B同时进入instance没有初始化 创建两个实例。每次获取实例都要进行同步,因此效率低。

    public class Singleton01 {
        // 定义一个私有类的静态变量
        private static Singleton01 instance;
        // 私有化构造函数
        private Singleton01() {}
        // 提供一个共有的获取实例的静态方法
        public static synchronized Singleton01 getInstance() {
            if (instance == null) {
                instance = new Singleton01();
            }
            return instance;
        }
    }

        总结:线程安全(添加了synchronized 关键字) 、 懒加载 (执行时才初始化)、效率低(每次都要进行同步)    

  2. 饿汉式

    加载时候就初始化,没有线程安全问题,效率高、没有懒加载,如果该实例没有被使用过,会造成内存浪费。

    public class Singleton02 {
        // 定义一个私有类的静态变量并初始化
        private static Singleton02 instance = new Singleton02();
        // 私有化构造函数
        private Singleton02() {}
        // 提供一个共有的获取实例的静态方法
        public static Singleton02 getInstance() {
            return instance;
        }
    }

        总结:线程安全(不存在线程问题)、非懒加载、 效率高

  3. 双重监测机制(DCL)

    只有使用时,才进行初始化,达到懒加载效果、只有在初始化时候才会进行加锁、没有线程问题、也不会影响效率。

    public class Singleton03 {
        // volatile 使每次使用都从主存中取而不是工作内存中获取
        private static volatile Singleton03 instance;
        // 私有化构造函数
        private Singleton03() {};
        // 提供一个共有的获取实例的静态方法
        public static Singleton03 getInstance() {
            if(instance == null) {
                // 如果instance等于空 则同步(加锁)
                // 只能有一个线程得到资源执行。另一个线程等待当前线程执行完才能执行该代码块。
                // 只有初始化的时候为空 所有只加锁一次
                synchronized (Singleton03.class) {
                    // 第二次进行判断
                    if(instance == null) {
                        instance = new Singleton03();
                    }
                }
            }
            return instance;
        }
    }

         总结:线程安全(初始化时加锁)、懒加载、效率高

  4. 静态内部类(延迟初始化占位类)

    只有使用时候,调用静态内部类进行初始化、达到懒加载效果。没有线程问题(类变量的赋值语句,在编译生成字节码的时候写在<clinit>()中,初始化单线程调用<clinit>()完成变量的赋值)、效率高。

    public class Singleton04 {
        // 定义一个静态内部类用来初始化静态变量
        private static class SingletonHolder{
            private static final Singleton04 instance = new Singleton04();
        }
        // 私有化构造函数
        private Singleton04() {}
        // 提供一个共有的获取实例的静态方法
        public static Singleton04 getInstance() {
            return SingletonHolder.instance;
        }
    }

        总结:线程安全、懒加载、效率高

  5. 枚举

    枚举线程安全只会装载一次,线程安全。不会被反射破坏单利。

    public class Singleton05 {
        // 私有化构造函数
        private Singleton05() {};
        // 枚举类型
        private enum SingletonEnum{
            INSTANCE;
            // 私有化成员变量
            private final Singleton05 instance;
            // 构造函数
            SingletonEnum(){
                instance = new Singleton05();
            }
            // 私有化方法
            private Singleton05 getInstance() {
                return instance;
            }
        }
        // 提供一个共有的获取实例的静态方法
        public static Singleton05 getInstance() {
            return SingletonEnum.INSTANCE.getInstance();
        }
    }

        总结:线程安全、懒加载、效率高

    

posted @ 2020-05-26 20:13  小小小小丑。  阅读(82)  评论(0编辑  收藏  举报