1.介绍
单例模式是应用最广泛的的模式之一,在应用这个模式时,必须保证单例对象的类只有一个实例。如在Android应用中,应该只有一个ImageLoader,ImageLoader含有线程池,缓存系统,网络请求,非常消耗资源,没有理由让它构造多个实例。这种不能自由构造对象的情况,就是单例模式的使用场景
2.单例模式的定义
确保一个类只有一个实例,而且自行实例化向整个系统提供这个实例。
3.使用场景
确保某个类有且只有一个实例对象场景,创建一个对象消耗的资源过多,如要访问IO和数据库等资源,这时就要考虑使用单例模式。
4.单例模式实现需要注意的几个关键点
3.1 构造函数不对外开放,一般为private。
3.2 通过一个静态方法或者枚举类返回单例类对象。
3.3 确保单例类的对象只有一个,特别是在多线程的情况下
3.4 确保单例类对象在反序列化时不会重新构建对象
5.单例模式实现的几种方式介绍
方式一:饿汉单例模式
public class SingletonTest { private static final SingletonTest mSingletonTest = new SingletonTest(); private SingletonTest(){} public static SingletonTest getInstance() { return mSingletonTest; } }
方式二:懒汉单例模式
public class SingletonTest { private static SingletonTest mSingletonTest = null; private SingletonTest(){} public static synchronized SingletonTest getInstance() { if(mSingletonTest == null) { mSingletonTest = new SingletonTest(); } return mSingletonTest; } }
优点:懒汉模式是单例只有在使用的时候才会被实例化,在一定程度上节约了资源。
缺点:第一次加载需要及时实例化,反应较慢,最大的问题是每次调用getInstance方法都进行同步,造成了不必要的开销,一般不推荐使用。
方式三:Double Check Lock(DCL)实现
public class SingletonTest { private static SingletonTest mSingletonTest = null; private SingletonTest(){} public static SingletonTest getInstance() { if(mSingletonTest == null) { synchronized (SingletonTest.class) { if(mSingletonTest == null) { mSingletonTest = new SingletonTest(); } } } return mSingletonTest; } }
DCL优点:资源利用率高,第一次执行getInstance时,单例对象才会被实例化,效率高,能保证线程安全,调用getInstance不用每次同步
缺点:第一次加载时反应稍慢,在高并发环境下也有一定的缺陷,发生概率较小。
DCL模式是目前使用最多的单例实现方式,它能够在需要时才实例化单例对象,并且在绝多数情况下能保证单例对象的唯一性,除非你的代码在并发场景非常
复杂或者低于JDK 6版本,否则,这种方式一定能满足需求
方式四:静态内部类单例模式
public class SingletonTest { private SingletonTest(){} public static SingletonTest getInstance() { return SingletonHolder.mSingletonTest; } private static class SingletonHolder { private static final SingletonTest mSingletonTest = new SingletonTest(); } }
第一次加载SingletonTest类时并不会初始化mSingletonTest,第一次调用getInstance方法会导致虚拟机加载SingletonHolder类,这种方式不仅能确保线程安全,也能保证对象的唯一性,同时也延迟了对象的实例化,是推荐使用的单例模式实现方式。
方式五:容器实现多个单例的管理
public class SingletonTest { private static Map<String, Object> mMap = new HashMap<String, Object>(); private SingletonTest() {} public static void registerService(String key, Object singleton) { if(!mMap.containsKey(key)) { mMap.put(key, singleton); } } public static Object getService(String key) { return mMap.get(key); } }
这种方式我们可以管理多种类型的单例,并且使用时通过统一的接口进行操作,降低了用户的使用成本,也对用户隐藏了使用细节,降低了耦合度。
上述几种创建单例的方式中,在一种情况下会出现重新创建对象的情况,那就反序列化。上述方法中如果想杜绝对象在反序列化时重新生成对象,那么必须加入如下方法:
private Object readResolve() throws ObjectStreamException { return sInstance; }
本文介绍了单例模式的概念、应用场景及其实现方式,包括饿汉模式、懒汉模式、双重检查锁定模式、静态内部类模式和容器管理单例模式。同时讨论了如何避免反序列化时创建新的实例。
677

被折叠的 条评论
为什么被折叠?



