Android 开发中常用的单例模式

单例模式

Posted by BY wangchuanwen on December 23, 2018

单例模式是java设计模式之一。这种模式涉及到单一的类,该类负责创建自己的对象,并确保是单一的对象。

特点

1.单例类只能有一个实例;

2.单例必须给自己创造唯一实例;构造函数是私有化,外部是无法实例化该类;

3.单例类必须给所以其他对象提供这一实例。

#优点

1.减少程序内部实例数目,节省系统资源;

2.全局使用的实例可以避免其频繁的创建与销毁;

3.避免对资源的过多占用。

#缺点

1.没有接口,不能继承

2.与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外部怎么来实例化。

#实现

##1.按照概念,我们实现一下单例模式,如下:

public class SingleInstanceClass { //创建自己的对象 private static SingleInstanceClass instanceClass=new SingleInstanceClass(); //私有构造方法 private SingleInstanceClass(){

}
//对外提供获取该类对象的方法
public static SingleInstanceClass getInstanceClass(){
    return instanceClass;
} }

这就完了?显然不可能;上面代码虽然实现的单例但如果程序中没有使用到这个对象,他依然会在编译时创建对应的实例,这样就浪费了资源。于是便有了懒加载的创建单例方式。

为了不浪费资源我们需要在使用给对象的时候再去创建它的实例对象,也就是懒加载模式

public class SingleInstanceClass { private static SingleInstanceClass instanceClass; //私有构造方法 private SingleInstanceClass(){

}

//对外提供获取该类对象的方法,且调用此方法时,创建实例
public static SingleInstanceClass getInstanceClass(){
    //保证唯一性
    if(instanceClass==null){
        instanceClass=new SingleInstanceClass();
    }
    return instanceClass;
} }

与放法一不同之处在于,只有当我们使用SingleInstanceClass.getInstanceClass()方法时才会实例化该对象。但是,如果是在多线程中呢?这种方式又有弊端了,多线程有可能依然会多次实例化这个对象。那为解决这个问题我们来看第三种方式。

懒加载,线程安全方式

public class SingleInstanceClass { private static SingleInstanceClass instanceClass; //私有构造方法 private SingleInstanceClass(){

}
//对外提供获取该类对象的方法,且调用此方法时,创建实例,加入线程锁
public static synchronized SingleInstanceClass getInstanceClass(){
    //保证唯一性
    if(instanceClass==null){
        instanceClass=new SingleInstanceClass();
    }
    return instanceClass;
} }

synchronized 同步锁,多线程并发时,同一时间只会执行一个线程。这种方法加了锁,会导致执行效率变低,于是乎为了提高运行效率,切又能保证线程安全;演变了第四种办法。

双检锁/双重校验锁

public class SingleInstanceClass { private volatile static SingleInstanceClass instanceClass; //私有构造方法 private SingleInstanceClass(){

}
//对外提供获取该类对象的方法,且调用此方法时,创建实例
public static  SingleInstanceClass getInstanceClass(){
    //保证唯一性
    if(instanceClass==null){
      synchronized (SingleInstanceClass.class){
          if(instanceClass==null){
              instanceClass=new SingleInstanceClass();
          }
      }
    }
    return instanceClass;
} }

一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:1. 保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。2. 禁止进行指令重排序

使用容器

public class SingletonManager { private SingletonManager() { }

 Map<String, WeakReference<Object>> data = new HashMap<String, WeakReference<Object>>();
 
 private static volatile SingletonManager instance = null;
 
 public static SingletonManager getInstance() {
    if (instance == null) {
        synchronized (SingletonManager.class) {
            if (instance == null) {
                instance = new SingletonManager();
            }
        }
    }
    return instance;
}

/** * 传递数据方法 * * @param key * @param object */

public static void registerInstance(String key, Object instance) {
    if (!instanceMap.containsKey(key)) {
        data.put(key, WeakReference<>(instance));
    }
}

/**
 * 获取数据方法
 *
 * @param key
 * @return
 */

public static Object getInstance(String key) {
    try {
        if(TextUtils.isEmpty(key)){
            return null;
        }
        WeakReference<Object> objectWeakReference = data.get(key);
        return objectWeakReference.get();
    } catch (Exception e) {
        return null;
    }
}

}

总结:以上就是我在开发中常用到的一些单例模式。

参考资料 https://juejin.im/post/58b4cd3261ff4b005cb23cd8 https://juejin.im/post/5a4b570cf265da430b7b9c55