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

一. 定义:

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

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

二. 写法套路

    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设计模式---单例设计模式)