美文网首页
设计模式之单例

设计模式之单例

作者: cpMark | 来源:发表于2017-09-17 10:27 被阅读0次

    定义:确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

    使用场景:在某些特定场景下我们需要确保某个类有且只有一个对象,比如创建一个对象需要消耗的资源过多,如要访问IO或者数据库等;还有就是一些全局的配置应该只有一个单一实例,如果有多个,那么配置项在使用时到底使用哪个实例的配置,这样容易导致一些稀奇古怪的异常。

    UML类图(以ImageLoader为例)
    单例(ImageLoader).png

    单例模式有如下几个关键点:

    1. 构造为private
    2. 通过静态方法getInstance()返回单例类的实例
    3. 注意在多线程环境下确保单例类的对象有且只有一个
    4. 确保单例类对象在反序列化时不会重新构建对象

    补充:序列化和反序列化
    序列化:将一个对象转为字节序列的过程称之为序列化(关键为ObjectOutputStream)
    反序列化:将字节序列转为对象的过程称之为反序列化(关键为ObjectInputStream)

    常见的创建单例的方式

    1. 饿汗式
    
    /**
     * 普通员工
     */
    class Staff1 {
        public void work() {
    
        }
    }
    
    /**
     * 副总裁
     */
    class VP1 extends Staff1 {
        @Override
        public void work() {
    
        }
    }
    
    /**
     * CEO 饿汗式单例
     */
    class CEO1 extends Staff1 {
        
        //先new出来
        private static final CEO1 sCeo = new CEO1();
    
        private CEO1() {}
    
        public static CEO1 getInstance(){
            //需要时直接返回
            return sCeo;
        }
    
        @Override
        public void work() {
    
        }
    }
    

    优点:节省运行时间
    缺点:浪费空间,因为在类加载时就会创建实例

    1. 懒汉式
    /**
     * CEO 懒汗式单例
     */
    class CEO2 extends Staff2 {
        
        //声明私有的静态单例变量
        private volatile static CEO2 sInstance;
    
        private CEO2() {}
    
        /**
         * 懒汉式,双重保护锁机制
         * @return
         */
        public static CEO2 getInstance(){
           //避免不必要的同步,只有在实例未初始化的情况下才同步实例化(判断需不需要同步)
            if(sInstance == null){
                synchronized (Singleton02.class){
                    //在null情况下才创建实例(判断需不需要实例化单例对象)
                    if(sInstance == null){
                        sInstance = new CEO2();
                    }
                }
            }
    
            return sInstance;
        }
    }
    

    优点:只有在使用时才会被实例化,在一定程度上节约了资源
    缺点:(1)第一次加载时需要及时进行实例化,反应稍慢 (2)由于Java编译器允许处理器乱序执行,如果线程A先将声明对象sInstance指向分配的内存空间,然后才去调用单例的构造,初始化成员字段,在未初始化之前如果切换到线程B,由于取到的sInstance不为null,这样就会出现异常。不过JDK1.5给出里解决本问题的方式,就是在声明sInstance时前面加上volatile关键字。

    1. 静态内部类
    
    /**
     * CEO 静态内部类实现单例
     */
    class CEO3 extends Staff3 {
        private CEO3() {}
    
       public static CEO3 getInstance(){
           return CEO3Holder.sInstance;
       }
    
    
        /**
         * 静态内部类
         */
        private static class CEO3Holder{
            private static final CEO3 sInstance = new CEO3();
        }
    }
    

    解决了双重保护锁可能失效的情况

    相关文章

      网友评论

          本文标题:设计模式之单例

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