单例模式

xiaoxiao2021-02-28  82

单例模式的定义:

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

单例模式的使用场景:

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

单例模式分类:

饿汉式 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的写法来完成单例模式。

转载请注明原文地址: https://www.6miu.com/read-53841.html

最新回复(0)