美文网首页
重修设计模式-单例模式

重修设计模式-单例模式

作者: 云逸Dean | 来源:发表于2017-11-24 14:50 被阅读0次

    重修设计模式-单例模式:

    0.修前叨叨:

    设计模式,一共23个.从今天开始,我打算每天抽空重修一个,方便自己的记忆以及更深入的理解.
    单例模式算是接触比较多的一个东西.以前,用的比较多.对于这个东西,起初觉得比较简单,只是对于重量级实例的封装容器的方式.现在,回头再来看,发现细节远不止这些.

    1.概念:

    单例模式,也叫单子模式,是一种常用的软件设计模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息。这种方式简化了在复杂环境下的配置管理。

    2.深挖细节:

    单例模式,会在多种场景下使用,所需的实现方式和要求也各不相同.

    2.1饿汉法:

    public class Singleton {   
        private static Singleton = new Singleton();
        private Singleton() {}
        public static getSignleton(){
            return singleton;
        }
    }
    

    故名思议,一看就是没吃饱.所以,在jvm启动的时候通过在class初始化的连接过程中进行赋值.其他调用的地方就可以放心使用,完全不用害怕线程的影响啦.但是,这个方式如果遇到需要延迟加载的类,那就不太合适了.这种需要延迟加载的单例,就需要下面的懒汉来处理.

    2.2懒汉法:

    2.2.1线程不安全:

    public class Singleton {
        private static Singleton singleton = null;
        private Singleton(){}
        public static Singleton getSingleton() {
            if(singleton == null) {//check&pro 明显的线程不安全点
                    singleton = new Singleton();
            }
            return singleton;
        }
    }
    

    上面的代码,在单线程使用的情况下是没有任何问题的.但是,被多线程使用的话,这个singleton对象会有被多次初始化的风险.因为,我们使用懒汉式的单例模式必然是有一个类加载比较消耗资源,我们连开机的时候都不想加载他.当被多次初始化的话,会对程序的性能产生很大的影响.

    2.2.2线程安全:

    public class Singleton {
        private static Singleton singleton = null;
        private Singleton() {
        }
    
        public static Singleton getSingleton() {
           synchronized (Singleton.class){
                if(singleton == null){
                    singleton = new Singleton();
                }
            }
            return singleton;
        }
    }
    

    咯,上面的代码里面加了个synchronized关键字,将本对象锁住以后就可以在判断的时候避免发生脏数据干扰,同时,由于单例模式的对象初始化一般都比较耗时,这时如果有其他线程也来获取的话可以阻塞住,直到单例创建完成以后再返回对象.但是,这也产生了新的问题,就是多线程跑到这里都变成了单线程了.接下来我们就会介绍一种兼顾线程安全和性能的实现思路

    2.2.3线程安全和性能兼顾的:

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

    上述代码,会在多线程获取单例时先判断是否有对象,如果有就不会去同步直接返回.如果没有就会去走同步check和处理.这样的处理方式兼顾了线程安全和单例实例生成后的多线程性能.但是,整个对象是存在的判断是基于volatile这个关键字的可见性和不可变性.经过查询的资料,volatile的代码不可变性实际上是在jdk1.5以后才真正的实现的,所以这个写法在jdk1.5及其以下的版本中使用是线程不安全的.

    2.3静态内部类&枚举法

    由于这2种方法具体的原理我不太熟悉,后面在更加深入了解原理后再补全.

    相关文章

      网友评论

          本文标题:重修设计模式-单例模式

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