单例模式

单例模式的定义:

  • 确保一个类只有一个实例,通过自行实例化向整个系统提供这个实例。

单例模式的使用场景:

  • 确保某个类有且只有一个对象的场景,避免产生对歌对象消耗过多资源,或者某种类型的对象有且只有一个

单例模式分类:

  • 饿汉式
private static final Singleton mInstance = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
    return mInstance;
}

这个实现的核心在于将Singleton类的构造方法私有化,使得外部程序不能通过构造函数来构造Singleton对象。

  • 懒汉式
private static Singleton mInstance;
private Singleton() {
}
public static synchronized Singleton getInstance() {
    if (mInstance == null) {
        mInstance = new Singleton();
    }
    return mInstance;
}

同步方法最大问题是每次调用getInstance()方法都会进行同步,造成不必要的同步开销。这种模式不建议使用。

  • Double Check Lock(DCL)单例
private static Singleton mInstance;
private Singleton() {
}
public static Singleton getInstance() {
    if (mInstance == null) {
        synchronized (Singleton.class) {
            if (mInstance == null) {
                mInstance = new Singleton();
            }
        }
    }
    return mInstance;
}

优点,里面加了非空判断,第一次加载后,每次调用getInstance方法不会进入同步代码块。同步里面的非空判断,原因是两个线程A,B都执行到同步代码块时,当A线程创建了对象后,切换到B线程,B现场如果没有非空判断也会创建新的对象。
缺点,由于java内存模型的原因偶尔会失败,在高并发环境有一定的DCL失效。配合volatile关键字使用。

  • 静态内部类单例
private Singleton() {
    }
public static Singleton getInstance() {
    return Singleton.SingletonHolder.mInstance;
    }
/**
*静态内部类
 */
private static class SingletonHolder{
    private static final Singleton mInstance = new Singleton();
}

第一次加载Singleton类时并不会初始化mInstance,只有在第一次调用Singleton的getInstance方法时mInstance才会初始化。第一次调用getInstace方法会导致虚拟机加载SingletonHolder类。这种方式能够确保线程安全,也能保证单例的唯一性,同时延迟了单例的实例化,所以推荐使用的单例实现方式。

  • 枚举单例
public enum Singleton {
        INSTANCE;   
}

枚举单例最大的优点,枚举在java中与普通的类一样,不仅能够有字段,自己的方法。最重要的是枚举实例的创建是线程安全的。任何情况都是一个实例(反序列化不会重新创建生成一个对象)。

  • 容器管理单例
private static Map<String, Object> objMap = new HashMap<>();
private SingletonManager(){}
public static void registerService(String key,Object instance){
    if (!objMap.containsKey(key)) {
        objMap.put(key, instance);
    }
}
public static Object getService(String key){
    return objMap.get(key);
}

优点通过统一方法操作获取,降低了用户的使用成本,也对用户隐藏了具体实现,降低耦合度。

Android源码中的单例模式

  • 软键盘管理InputMethodManager
public static InputMethodManager getInstance() {
   synchronized (InputMethodManager.class) {
      if (sInstance == null) {
          IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE);
          IInputMethodManager service = IInputMethodManager.Stub.asInterface(b);
          sInstance = new InputMethodManager(service, Looper.getMainLooper());
      }
   return sInstance;
  }
}

是第三种单例模式,只是同步代码块外面没有if判空处理。另外Android中Application不是单例模式,构造方法是公共的可以实例化对象,但app中可以只有一个实例。

单例模式运用

  • Glide第三方图片加载类库
 private static volatile Glide glide;
  public static Glide get(Context context) {
    if (glide == null) {
      synchronized (Glide.class) {
        if (glide == null) {
          initGlide(context);
        }
      }
    }
    return glide;
  }

第三方类库Glide用的是第三种单例,在高并发的时候有几率会出现DCL失效,在JDK1.5之后,SUN官方调整了JVM,具体化了volatile,在给它的变量名加上volatile修饰符后,可以使用DCL的写法来完成单例模式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值