美文网首页玩转设计模式
第一章——单例设计模式

第一章——单例设计模式

作者: 博尔特uncle | 来源:发表于2017-10-23 16:10 被阅读0次

    好久没写博客了,以前在CSDN上写过一篇servlet,jsp运行原理,妈的当时计划的很好一周一篇,然后结果就呵呵了,换了新老板已经快3个月了,项目已经稳定线上运行,闲的无事可做,难道这就是程序员追求的生活吗?感觉快废了,现在哪有持续稳定的工作啊?总要找点事做,充实一下自己内心寂寞的灵魂。得了不扯淡了.

    本系列文章主要是学习秦小波的<<设计模式之禅>>笔记和总结感悟,便于自己翻看学习和与各位朋友交流。

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


    QQ20171023144648.png

    相信这个UML类图有经验的程序员都看的懂,通过一个私有的构造方法确保一个应用中只产生一个实例,并且自行实例化这个实例。
    单例通用代码:
    public class CommonSingleton {
    private static CommonSingleton mInstance = new CommonSingleton();

    public static CommonSingleton getInstance() {
        return mInstance;
    }
    private CommonSingleton() {
    
    }
    public static void sayHello() {
        System.out.println("Hello 我是皇帝我独尊");
    }
    
    public static void main(String[] args) {
        CommonSingleton.getInstance().sayHello();
    }
    

    }
    单例模式的应用:

    单例的特点是在内存中只有一个实例存在,并且常驻内存,如果一个对象需要频繁的创建和销毁时,为了节省内存的开支我们可以用单例,但要注意内存泄漏的可能,比如Android 常见的上下文泄露,
    单例模式可以避免对资源的多重占用,例如一个写文件动作,由于只有一个实例存在内存中,避免对同一个资源文件的同时写操作。
    任何设计模式都有它特定的应用场景,单例也有它的不足,只需要根据具体需求选择即可:
    单例模式一般没有接口,扩展很困难,若要扩展,除了修改代码基本上没有第二种途径可以实现。
    单例模式跟六大设计原则的单一职责原则相冲突,一个类应该只实现一个逻辑,而不关心它是否是单例的,是不是要单例取决于环境,单例模式把“要单例”和业务逻辑融合在一个类中。
    单例模式一般不实现接口,扩展性不强.

    单例设计模式注意事项:
    使用单例首先是需要在特定的场景中,比如生成生成唯一的序列号,缓存一些数据,创建对象需要消耗资源过多访问io操作,数据库操作等,一些app中保存的大量的static 常量可以用单例也可以直接声明为static.

    单例使用应该注意高并发的问题,并发场景中,可能就会产生两个实例对象,这就跟我们单例设计的初衷相违背;通常解决方式是在使用syachronized关键字加锁,或者使用同步代码块方式,但都不是最优解;下面列出几种常见的写法:
    No1.

      private static CommonSingleton mInstance;
       public static CommonSingleton getInstance() {
        if (mInstance == null) {
            mInstance = new CommonSingleton();
        }
        return mInstance;
    }
    private CommonSingleton() {
    }
    public static void sayHello() {
        System.out.println("Hello 我是皇帝我独尊");
    }
    

    俗称懒汉式,没有线程安全性可言,
    No2.

        private static CommonSingleton mInstance;
    public static synchronized CommonSingleton getInstance() {
        if (mInstance == null) {
            mInstance = new CommonSingleton();
        }
        return mInstance;
    }
    
    private CommonSingleton() {
    }    
    

    懒汉式,线程安全的,但是效率极低
    No3.

    private static CommonSingleton mInstance = new CommonSingleton();
    public static CommonSingleton getInstance() {
        // if (mInstance == null) {
        // mInstance = new CommonSingleton();
        // }
        return mInstance;
    }
    private CommonSingleton() {
    }
    

    饿汉式,基于classloder机制避免了多线程的同步问题,在类加载时候初始化,

    No4。

    private static CommonSingleton mInstance ;
    static {
        mInstance = new CommonSingleton();
    }
    
    public static  CommonSingleton getInstance() {
        // if (mInstance == null) {
        // mInstance = new CommonSingleton();
        // }
        return mInstance;
    }
    
    private CommonSingleton() {
    
    }
    

    饿汉式基因变异体,实际上是一样的都是通过类加载时候实例化.
    No5.

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

    这是一种双重校验式,有效解决线程安全问题,市面上使用的比较多

    虽说No5写法校验已经很强了,但是有一种情况的发生,jvm虚拟机可能出现的指令重排序影响双重检查加锁(double-checked locking)的正确性。
    我们只需要加一个volatile关键字即可保证指令重排序的正确性。具体原理请看这哥们的介绍的很详细膜拜一下牛人http://www.cnblogs.com/dolphin0520/p/3920373.html

    private volatile static CommonSingleton mInstance;
    

    哎我操都4点了,今天就到这吧,不寂寞了休息一下明天继续,

    相关文章

      网友评论

        本文标题:第一章——单例设计模式

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