花式写单例之单例的六种写法

作者: EnjoyAndroid | 来源:发表于2017-11-23 14:30 被阅读182次

    一、前言

           单例模式是一种常用的设计模式,其定义是单例对象类只允许一个实例存在,实现的核心原理是构造函数私有化。使用单例可以节省内存开销,也是现实场景中的一种映射,比如一台打印机同时只能运行一个打印任务,一个公司只有一个CEO等场景。

    二、实现步骤

    2.1 构造函数私有化;
    2.2 提供一个静态方法获取实例(需要注意多线程问题)。

    三、写法

    3.1 饿汉式(线程安全)

    public class Singleton {
    
        private static final Singleton instance = new Singleton();
    
        private Singleton() {
        }
    
        public static Singleton getInstance() {
            return instance;
        }
    }
    
    

    优点:简单粗暴、类加载的时候就初始化完成,线程安全;
    缺点:类加载的时候就已经完成初始化,如果该对象使用时机比较晚,或者始终没有用到,会造成不必要的内存资源浪费。

    3.2 懒汉式(线程不安全)

    public class Singleton {
    
        private static Singleton instance;
    
        private Singleton() {
        }
    
        public static Singleton getInstance() {
            if (instance == null) {
                instance = new Singleton();
            }
            return instance;
        }
    }
    

    优点:延迟初始化,避免了不必要的内存开销;
    缺点:线程不安全。

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

    public class Singleton {
    
        private static Singleton instance;
    
        private Singleton() {
        }
    
        public static synchronized Singleton getInstance() {
            if (instance == null) {
                instance = new Singleton();
            }
            return instance;
        }
    }
    

    优点:延迟初始化,避免了不必要的内存开销,且线程安全;
    缺点:效率偏低,每次获取实例都进行同步锁,事实上只需要在第一次new对象的时候同步锁就行了,后续想获取实例可以直接返回。

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

    public class Singleton {
    
        private static volatile Singleton instance;
    
        private Singleton() {
        }
    
        public static Singleton getInstance() {
            if (instance == null) {
                synchronized (Singleton.class) {
                    if (instance == null) {
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }
    }
    
    

    这种方式是对3.3的一个优化,兼顾效率和线程安全,也是比较常用的一种写法。

    3.5 静态内部类(线程安全)

    public class Singleton {
    
        private static Singleton instance;
    
        private Singleton() {
        }
    
        public static Singleton getInstance() {
            return SingletonHolder.INSTANCE;
        }
    
        private static class SingletonHolder {
    
            private static final Singleton INSTANCE = new Singleton();
        }
    
    }
    

    这种方式兼顾了延迟初始化,线程安全,是一种比较推荐的写法。

    3.6 枚举(线程安全)

    public enum Singleton {
    
        INSTANCE;
    
    }
    

    枚举是JDK1.5之后推出的一个新特性,该写法是《Effective Java》推荐的一种写法,简单粗暴、高效,线程安全,缺点是阅读性不是很强,在Android上使用枚举会有一定的性能开销,官方并不建议大规模使用枚举。

    四、适用场景

    4.1 创建对象耗时或者耗费资源过多,但又需要频繁用到;
    4.2 需要频繁的进行创建和销毁的对象;
    4.3 工具类对象。
    

    五、总结

           单例的写法很多,以上列举了比较常见的写法,具体用的时候需要根据自己应用的实际需求来写,我个人比较推荐3.4懒汉式(线程安全,同步代码块)3.5 静态内部类(线程安全)的写法。

    相关文章

      网友评论

        本文标题:花式写单例之单例的六种写法

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