android设计模式之单例模式

单例模式介绍

单例模式是使用最广泛的一种设计模式,在这种设计模式中,单例对象的类必须保证有且只有一种实力存在。在我们的应用中往往会存在这么一个全局对象,用来统一处理某种行为,如网络请求、数据缓存、图片加载等。像这种情况就没必要每次使用时都构造实例,而往往采用单例模式

应用场景

某种类型的对象有且只有一个对象,避免产生多个对象消耗更多的资源。

实现单例模式有如下关键点:

  1. 构造函数不对外开放,一般都是私有的。
  2. 对外提供一个静态的公共方法或枚举返回单例对象。
  3. 确保单例对象有且只有一个,如多线程情况下。
  4. 确保单例对象在反序列化时不会重新创建对象。

单例模式的实现方式

饿汉模式:这是最常见也是最简单的是想方式,在调用getInstance前,在声明静态对象时就进行了初始化。

public class Singleton {
    private static Singleton instance=new Singleton();
    
    private Singleton(){ }
    public static Singleton getInstance(){
        
        return instance;
    }
}

懒汉模式:相对于饿汉不同的是,在用户第一次调用getInstance时才进行初始化,实现方式如下

public class Singleton {
    private static Singleton instance=new Singleton();
    
    private Singleton(){ }
    public synchronized static Singleton getInstance(){
        if(instance==null) {
            instance=new Singleton();   
        }

        return instance;
    }
}

通过观察在getInstance方式中添加了synchronized关键字,也就是说getInstance是个同步方法,保证在多线程情况下保证了单例的唯一性。但是这里有个问题——即便instance已经初始化了,每次调用getInstance方法还是要进行同步,而方法同步都会消耗资源,造成不必要的开销。这也是懒汉单例模式存在的一个最大问题。

Double check Lock(双重校验):这种方式是在懒汉、饿汉式的基础的升级,既能够在需要时才初始化,又能保证线程安全,而且单例对象初始化后不需要进行同步锁。

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

DCL的特点在getInstance方法中的两次判空:
第一次判断主要是避免不必要的同步锁;
第二次判断是在null情况下创建实例;
在 instance=new Singleton();这条语句里,大致做了三件事:

  1. 给Singleton的实例分配内存
  2. 调用Singleton的构造函数
  3. 将instance对象指向分配的内存空间
    如果按照正常的1、2、3步骤顺利执行,那我们能顺利获得实例对象。但是 编译器为了优化程序指令加快cpu处理速度,会有指令重排序——也就是说上面的三步可能会1、3、2顺序。如果线程A执行到3完毕、2未完成之前。被切换到线程B,这个时候instance因为在线程A内已经执行了3,这个实际instance则不会为空。所以线程B直接获取instance,在使用的时候就会报错。
    这时只需将instance的定义改为private volatile static Singleton instance = null;就可以保证instance对象每次都要从主内存中获取。

静态内部类单例模式
当第一次加载Singleton类时并不会初始化instance,只有在第一次调用Singleton的getInstance方法才会导致instance被初始化。因此第一次调用getInstance方法会导致虚拟机加载SingletonHolderl类,同时保证了延迟加载、线程安全、对象的唯一性,所以推荐使用这种方式实现单例模式。

public class Singleton {
    private Singleton(){ }
    public static Singleton getInstance(){
        return SingletonHolder.instance;
    }
    private static  class SingletonHolder{
        private static final  Singleton instance=new Singleton();

    }
}

枚举单例

public enum SingletonEnum {
    INSTANCE;
    public void doSomeThing(){
        System.out.println("do sth");
    }

}

容器单例模式

public class SingletonManager {
    private static Map objectMap= new HashMap<>();
    private SingletonManager(){}
    public static  void registerService(String key,Object instance){
        objectMap.put(key,instance);
    }
    public static Object getService(String key){
        return objectMap.get(key);
    }
}

你可能感兴趣的:(android设计模式之单例模式)