美文网首页
单例模式

单例模式

作者: AD刘涛 | 来源:发表于2020-04-04 15:43 被阅读0次

    单例模式适用场景

    1. 无状态的工具类:比如日志工具类,不管是在哪里使用,我们需要的只是它帮我们记录日志信息,除此之外,并不需要在它的实例对象上存储任何状态,这时候我们只需要一个实例对象即可。
    2. 全局信息类:比如我们在一个类上记录网站的访问次数,我们不希望有的访问被记录在对象A上,有的却记录在对象B上,这时候我们就希望这个类成为单例。

    饿汉式

    第一种实现方式
    package singleton;
    
    /**
     * 描述: 饿汉式(静态常量)[可用,线程安全]
     * 从代码中我们看到,类的构造函数定义为private的,保证其他类不能实例化此类,然后提供了一个静态实例并返回给调用者。
     * 其实现简单,并且在类加载的时候就对实例进行创建,实例在整个程序周期都存在。
     *
     * 优点:  只在类加载的时候创建一次实例,不会存在多个线程创建多个实例的情况,避免了多线程同步的问题。
     * 缺点:  即使这个单例没有用到也会被创建,而且在类加载之后就被创建,这样一来就存在着内存浪费。
     * 适用于:这种实现方式适合占用内存比较小的单例对象,且在初始化时就会被用到的情况。但是,如果单例占用的内存比较    大,或单例只是在某个特定场景下才会用到,使用饿汉模式就不合适了,这时候就需要用到懒汉模式进行延迟加载。
     */
    public class Singleton1   {
    
        private final static Singleton1 instance = new Singleton1();
    
        private Singleton1(){
    
        }
    
        public static Singleton1 getInstance(){
            return instance;
        }
    }
    
    
    第二种实现方式
    /**
     * 描述:     饿汉式(静态代码块)(可用,与上个案例实现原理基本相似,也是线程安全)
     *
     */
    public class Singleton2 {
    
        private final static Singleton2 INSTANCE;
    
        static {
            INSTANCE = new Singleton2();
        }
    
        private Singleton2() {
        }
    
        public static Singleton2 getInstance() {
            return INSTANCE;
        }
    }
    

    懒汉式

    第一种实现方式
    package singleton;
    
    /**
     * 描述:     懒汉式(线程不安全)
     *
     * 优点:懒汉模式中单例是在需要的时候才去创建的,如果单例已经创建,再次调用获取接口将不会重新创建新的对象,而是直接返回之前创建的对象。
     * 缺点:但是这里的懒汉模式并没有考虑线程安全问题,在多个线程可能会并发调用它的getInstance()方法,导致创建多个实例,因此需要加锁解决线程同步问题
     * 适用于:如果某个单例使用的次数少,并且创建单例消耗的资源较多,那么就需要实现单例的按需创建,这个时候使用懒汉模式就是一个不错的选择。
     */
    public class Singleton3 {
    
        private static Singleton3 instance;
    
        private Singleton3() {
    
        }
    
        // 在获取类对象的时候进行初始化,
        // 但是这里的懒汉模式并没有考虑线程安全问题,
        // 在多线程环境下可能会并发调用它的getInstance()方法,导致创建多个实例
        public static Singleton3 getInstance() {
          // 如果多线程并行if (instance == null)这行代码,则会多次创建instance
            if (instance == null) {
                instance = new Singleton3();
            }
            return instance;
        }
    }
    
    
    第二种实现方式
    package singleton;
    
    /**
     * 描述:     懒汉式(线程安全)(不推荐)
     */
    public class Singleton4 {
    
        private static Singleton4 instance;
    
        private Singleton4() {
    
        }
    
        // 由于synchronized关键字的使用会造成该方法效率极低,因此不推荐使用
        public synchronized static Singleton4 getInstance() {
            if (instance == null) {
                instance = new Singleton4();
            }
            return instance;
        }
    }
    
    
    第三种实现方式
    package singleton;
    
    /**
     * 描述:     懒汉式(线程不安全)(不推荐)
     */
    public class Singleton5 {
    
        private static Singleton5 instance;
    
        private Singleton5() {
    
        }
    
        // 事实上,该方法依旧是线程不安全。why?原因是当多个线程走到 "if (instance == null)"这里后,
        // 会造成线程阻塞。但第一个线程运行结束后,释放锁后,第二个线程依旧会进入该方法,依旧会创建新的对象。
        // 所以即使加入synchronized方法,线程依旧不安全。
        public static Singleton5 getInstance() {
            if (instance == null) {
                synchronized (Singleton5.class) {
                    instance = new Singleton5();
                }
            }
            return instance;
        }
    }
    
    
    第四种实现方式
    package singleton;
    
    /**
     * 描述:     双重检查(推荐使用)
     */
    public class Singleton6 {
        /**
         *  之所以使用volatile关键字是为了阻止重排序,以及可见性,原因是创建对象并非原子操作。
         *  因为创建对象包含3个步骤:1. 新建一个空的Person对象。2. 把这个对象的地址指向引用。
         *  3.执行Person的构造函数。
         */
        private volatile static Singleton6 instance;
    
        private Singleton6() {
    
        }
    
        /**
         *  该方法线程安全。why?原因是当多个线程走到 "if (instance == null)"这里后,
         *  会造成线程阻塞。但第一个线程运行结束后,释放锁后,第二个线程依旧会进入该方法,
         *  一旦线程走到synchronized代码段后都会再次判断实例是否创建,所以线程安全。
         */
        public static Singleton6 getInstance() {
            if (instance == null) {
                synchronized (Singleton6.class) {
                    // 一旦线程走到了都会判断实例是否创建
                    if (instance == null) {
                        instance = new Singleton6();
                    }
                }
            }
            return instance;
        }
    }
    
    

    相关文章

      网友评论

          本文标题:单例模式

          本文链接:https://www.haomeiwen.com/subject/mxejphtx.html