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

Android设计模式---单例设计模式

作者: liys_android | 来源:发表于2019-01-27 13:19 被阅读24次

    一. 定义:

    一种最最常见的一种模式,保证整个程序中只有一个实例 
    

    主要思想: 保证程序只有一个实例就可以了,不要仅限于目前主流的写法,如果没有更好的办法,那就只能用目前主流的方法了。

    二. 写法套路

        1. 构造函数私有,防止在外部 new 对象
        2. 内部必须提供一个静态的方法,让外部调用
        3. 线程安全问题.
    

    三. 目前常见的写法

    1.饿汉式
    /**
     * liys 2019-01-11
     * 饿汉式
     */
    public class Single1 {
        private static Single1 instance = new Single1();
    //    static{ //这样写也可以
    //        instance = new Single1();
    //    }
        private Single1() {}
        private static Single1 getInstance(){
            return instance;
        }
    }
    

    优点: 写法比较简单,就是在类装载的时候就完成实例化。避免了线程同步问题。
    缺点: 在类装载的时候就完成实例化。如果从始至终从未使用过这个实例,则会造成内存的浪费。例如: A和B页面打开的时候才会用到, 用户从未打开A和B页面, 这样就会造成内存的浪费.

    2. 懒汉式(同步锁DCL)
    /**
     * liys 2019-01-11
     * 懒汉式 (DCL)
     */
    public class Single2 {
        private static volatile Single2 instance;
        private Single2() {}
        private static Single2 getInstance(){
            if(instance == null){ //保证效率
                synchronized(Single2.class){ //保证线程安全
                    if(instance == null){
                        instance = new Single2();
                    }
                }
            }
            return instance;
        }
    }
    

    优点: 用到的时候才初始化对象, 效率高, 不会造成内存浪费.
    缺点: 容易造成线程安全问题, 并发效率低.
    注意: volatile的使用, 后面会单独讲.

    3. 静态内部类
    /**
     * liys 2019-01-11
     * 静态内部类
     */
    public class Singleton {
    
        private Singleton() {}
    
        private static class SingletonHolder{
            private static volatile Singleton INSTANCE = new Singleton();
        }
    
        private static Singleton getInstance(){
            return SingletonHolder.INSTANCE ;
        }
    }
    

    优点: 集合了饿汉式和懒汉式的优点,效率高, 线程安全, 占用内存少.
    缺点: 无法传递参数.

    4. 枚举
       据说占内存会比较多,了解的不深, 不做介绍.
    

    四. volatile关键字

    作用:
    1. 防止重排序
    我们先看new对象的时候jvm做了什么? 例如:

    instance = new Single2();
    

    这行代码,其实在jvm里面的执行分为三步:
    1.在堆内存开辟一块内存空间。
    2.在堆内存中实例化Single2里面的各个参数。
    3.把对象指向堆内存空间。
    正常的执行顺序应该是1.2.3. 但是jvm存在乱序执行功能,所以可能在2还没执行时就先执行了3.
    例如: 线程A执行了1.3, 这个时候切换线程B, 这时候instance 已经不是null了, 所以线程B直接拿instance 来用, 这个时候就会出现问题.
    加了volatile关键字, 执行顺序肯定就是1.2.3.

    2. 线程的可见性
    可见性是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。

    instance = new Single2();
    

    例如: 线程A初始化了instance , 这个时候切换到线程B了, 如果不加volatile关键字的话, 线程B有可能认为instance还是null, 因为每一个线程都有自己的缓存区, 线程A会先把instance 存到缓存区, 然后才去给主存里面赋值. 而B直接读取主存中的instance 所以有可能出现null.
    这就是可见性问题,线程A对变量instance 修改了之后,线程B没有立即看到线程A修改的值。
    这里只是做了简单的介绍, 想要了解的更深入,可以参考:https://www.cnblogs.com/dolphin0520/p/3920373.html

    相关文章

      网友评论

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

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