狐彻设计模式学习笔记(一)—— 单例模式(Singleton)

it2023-10-14  70

设计模式(一)—— 单例模式(Singleton)

基于《Android 源码设计模式 解析与实战》第二版(何红辉 关爱民 著)的学习笔记

定义

确保某一类只有一个实例,且自行实例化并向整个系统提供这个实例

使用场景

需确保某个类有且只有一个对象的场景需避免产生多个对象消耗过多资源某类型对象应有且只有一个实例

如创建一个对象需要消耗的资源过多(IO、网络交互、数据库)

角色

Client —— 高层客户端Singleton —— 单例类

特点

构造函数不对外开放,一般为private通过一个静态方法或枚举类返回单例对象确保单例类的对象有且只有一个,尤其是并发环境下确保单例对象在反序列化时不会重新构建对象

实现方式

1. 饿汉模式模式

在生命静态对象时就已经初始化。因急于初始化,被称为饿汉模式

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

2. 懒汉模式

生命一个静态对象,并在用户第一次调用静态获取方法时进行初始化,用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都会进入同步,造成不必要的资源消耗

3. 双重锁模式、Double Check Lock (DCL)

在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?

小结

优点: 减少内存开支减少性能开销避免资源多重占用共享资源访问 缺点: 一般没有接口,拓展困难。若要拓展基本上只能修改代码若单例持有Context,则可能造成内存泄漏。最好传递Application Content
最新回复(0)