基于《Android 源码设计模式 解析与实战》第二版(何红辉 关爱民 著)的学习笔记
确保某一类只有一个实例,且自行实例化并向整个系统提供这个实例
如创建一个对象需要消耗的资源过多(IO、网络交互、数据库)
在生命静态对象时就已经初始化。因急于初始化,被称为饿汉模式
class Singleton { private static final Singleton instance = new Singleton(); private Singleton(){} static Singleton getInstance(){ return instance; } }生命一个静态对象,并在用户第一次调用静态获取方法时进行初始化,用sychronized关键字将获取方法标记为同步方法。
class Singleton { private static final Singleton instance = null; private Singleton(){} static synchronized Singleton getInstance(){ if (instance == null) instance = new Singleton(); return instance; } } 优点:只有在使用时才会被实例化,一定程度的节省资源缺点:即使instance已被初始化,每次调用getInstance都会进入同步,造成不必要的资源消耗在getInstance方法中对instance进行两次判空 第一次判空只要为避免不必要同步,第二次的判断则为了在未实例化的情况下实现实例化。
class Singleton { private static final Singleton instance = null; private Singleton(){} static Singleton getInstance(){ if (instance == null) { synchronized(Singleton.class) { if(instance == null) instance = new Singleton(); return instance; } } return instance; } } 优点: 资源库利用率高,既能够在需要时才初始化单例保证线程安全,且对象初始化后不再进行同步锁 缺点: 第一次加载反应稍慢高并发下可能发生DCL失效DCL失效: 在调用到Singleton()而在初始化instance前跳转到其他线程,并在该线程完成instance的赋值。此时切换回原线程,则会继续执行instance的初始化。从而导致出错。可以用volatile关键字解决此问题,不过该关键字也会影响性能。
为解决双重所失效(DCL失效)问题,可以用静态内部类的特性实现单例 只有在调用到静态内部类时,该静态内部类才会被虚拟机加载。
class Singleton { private Singleton(){} static Singleton getInstance(){ return SingletonHolder.instance; } static class SingletonHolder { private static final Singleton instance = new Singleton(); } } 第一次加载Singleton类时不会初始化instance第一次调用Singleton的getInstance方法时才会导致sInstance被初始化保证线程安全保证单例对象的唯一性延迟了单例的实例化是推荐使用的单例模式实现方式通过枚举类特性实现单例
enum SingletonEnum { INSTANCE; void doSomething() { System.out.printlin("do sth.") } } 枚举类在Java中与普通类是一样的,能拥有字段和自己的方法默认是线程安全的任何情况下都是一个单例容器形式的单例
class SingletonManager { private static Map<String, Object> objMap = new HashMap<>(); private SingletonManager(){} static void registerService(String key, Object instance) { if(!objMap.containsKey(key)) objMap.put(key, instance); } static Object getService(String key) { return objMap.get(key); } }代码很清晰,而且是不是看起来很像Context的getService?