美文网首页
单例模式的六种创建方式

单例模式的六种创建方式

作者: e小e | 来源:发表于2017-10-10 08:25 被阅读35次

    在使用java编码的过程中经常会去写单例模式,今天总结一下6种常见单例写法.

    饿汉模式

    public class HungerSingleton {
        private static HungerSingleton singleton = new HungerSingleton();
        private HungerSingleton() {
        }
        public static HungerSingleton getHungerSingletonInstance(){
            return singleton;
        }
    }
    

    评价:这种模式直接在类初始化的时候实例化单例,线程安全,但是没有延迟加载。

    懒汉模式

    public class LazySingleton {
        private static LazySingleton singleton;
        private LazySingleton() {
        }
        public static LazySingleton getLazySingletonInstance(){
            if (singleton == null){
                singleton = new LazySingleton();
            }
            return singleton;
        }
    }
    

    评价:这种模式在需要使用该对象的时候时候实例化单例,做到了延迟加载,节约内存,但是非线程安全。

    懒汉线程安全模式

    public class LazyThreadSafeSingleton {
        private static LazyThreadSafeSingleton singleton;
        private LazyThreadSafeSingleton() {
        }
        public synchronized static LazyThreadSafeSingleton getLazyThreadSafeSingletonInstance(){
            if (singleton == null){
                singleton = new LazyThreadSafeSingleton();
            }
            return singleton;
        }
        //或者
    public static LazyThreadSafeSingleton getLazyThreadSafeSingletonInstance(){
            synchronized (LazyThreadSafeSingleton.class){
                if (singleton == null){
                    singleton = new LazyThreadSafeSingleton();
                }
                return singleton;
            }
        }
    }
    
    

    评价:同时做到了线程安全,而且延迟加载,但是每次getLazyThreadSafeSingletonInstance都会使用synchronized关键字影响了效率.

    DCL模式模式

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

    评价:这里我们进行了双重check,第一次check没有synchronized关键字,比懒汉线程安全节约了效率,第二次check的时候加入了synchronized关键字再一次进行了一次是否为null的判断,这样保证在多线程并且mInstance都为null情况下进行重复创建。注意mInstance = new DclSingleton()这句代码,它实际上并不是一个原子操作,这条代码最终会编译成多条汇编指令,它大概会做三件事

    1. 给DclSingleton分配内存
    2. 调用DclSingleton构造函数,初始化成员字段
    3. 将mInstance对象指向分配的内存控件(此时mInstance就不是null了)
      上面2,3顺序是不能保证顺序执行的,也就是说顺序可能是123也有可能是132,也就是说在3执行完毕,2未执行完的情况,会存在其它线程调用getInstance()直接返回mInstance的情况。所以我们必须加上volatile关键字,保证不会出现132这种情况

    静态内部类模式

    public class StaticInnerSingleton {
        
        private StaticInnerSingleton(){
        }
    
        public static StaticInnerSingleton getInstance(){
            return StaticInnerHolder.sInstance;
        }
    
        public static class StaticInnerHolder{
            public static final StaticInnerSingleton sInstance = new StaticInnerSingleton();
        }
    }
    

    评价:这种单例模式简单,线程安全,并且延迟加载,推荐使用

    枚举模式

    public enum EnumSingleton {
        INSTANCE;
        public void doSomeThing(){
            System.out.println("do sth");
        }
    }
    

    评价:这种单例模式简单,线程安全

    总结:任何单例模式都是将构造函数私有化,对外提供统一获取唯一实例的接口,在选择哪种模式要考虑线程安全,延迟加载因素。

    相关文章

      网友评论

          本文标题:单例模式的六种创建方式

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