《Android源码设计模式解析与实战》读书笔记(二)
来源:互联网 发布:usb2.0端口 编辑:程序博客网 时间:2024/05/02 16:35
第二章、单例模式
单例模式应该是日常使用最为广泛的一种模式了。他的作用是确保某个类只有一个实例,避免产生多个对象消耗过多的资源。比如对数据库的操作时,就可以使用单例模式。
1.各种单例
(1)饿汉模式
public class Singleton { private static Singleton instance = new Singleton(); private Singleton (){ } public static Singleton getInstance() { return instance; } }
这种写法是在类装载时就实例化instance,他避免了多线程的同步问题。但是不能保证有别的方式去装载,没有达到懒加载。
(2)懒汉模式(线程不安全)
public class Singleton { private static Singleton instance; private Singleton (){ } public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
达到了懒加载,但是在多线程不能正常工作。
(3)懒汉模式(线程安全)
public class Singleton { private static Singleton instance; private Singleton (){ } public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
这种写法能够在多线程中很好的工作,但是每次调用getInstance方法都会进行同步,反应稍慢,还会造成不必要的开销,所以者这种不建议使用。
(4)DCL单例(双重检查锁定)
public class Singleton { private volatile static Singleton singleton; private Singleton (){ } public static Singleton getSingleton() { if (singleton == null) { synchronized (Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } } return singleton; } }
这种写法在getSingleton方法中对singleton进行了两次判空,第一次是为了不必要的同步,第二次是为了在null的情况下创建实例。我们会发现上面代码有一个volatile关键字,因为在这里会有DCL失效问题,原因是Java编译器允许处理器乱序执行。那么为了解决这个问题,在JDK1.5之后,具体化了volatile关键字,只要定义时加上他,可以保证执行的顺序,虽然会影响性能。这种方式第一次加载时会稍慢,在高并发环境会有缺陷,但是一般能够满足需求。
(5)静态内部类单例模式
public class Singleton { private Singleton (){ } public static final Singleton getInstance() { return SingletonHolder.INSTANCE; } /** *静态内部类 */ private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } }
这种是推荐使用的单例模式实现方式。当第一次加载Singleton类时并不会初始化INSTANCE,只有在第一次调用getInstance方法时才会导致INSTANCE被初始化。这种方式不仅能够保证线程安全,也能保证单例对象的唯一性,同时也延长了单例的实例化。
(6)枚举单例
public enum Singleton { INSTANCE; public void whateverMethod() { } }
这种方式是Effective Java作者Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象。
(7)使用容器实现单例模式
public class SingletonManager { private static Map<String, Object> objMap = new HashMap<String,Object>(); private Singleton() { } public static void registerService(String key, Objectinstance) { if (!objMap.containsKey(key) ) { objMap.put(key, instance) ; } } public static ObjectgetService(String key) { return objMap.get(key) ; }}
将多种单例类型注入到一个统一的管理类中,在使用时根据key获取对象对应类型的对象。这种方式使得我们可以管理多种类型的单例,并且在使用时可以通过统一的接口进行获取操作,降低了用户的使用成本,也对用户隐藏了具体实现,降低了耦合度。
2.Android源码中的单例模式
在Android系统中,我们经常会通过Context获取系统级别的服务,如WindowsManagerService、ActivityManagerService等,更常用的是一个LayoutInflater的类,这些服务会在合适的时候以单例的形式注册在系统中,在我们需要的时候就通过Context的getSystemService(String name)获取。
3.总结
优点:
(1)由于单例模式在内存中只有一个实例,减少了内存开支,特别是一个对象需要频繁的创建、销毁时,而且创建或销毁时性能又无法优化,单例模式的优势就非常明显。
(2)单例模式可以避免对资源的多重占用,例如一个文件操作,由于只有一个实例存在内存中,避免对同一资源文件的同时操作。
(3)单例模式可以在系统设置全局的访问点,优化和共享资源访问,例如,可以设计一个单例类,负责所有数据表的映射处理。
缺点:
(1)单例模式一般没有接口,扩展很困难,若要扩展,只能修改代码来实现。
(2)单例对象如果持有Context,那么很容易引发内存泄露。此时需要注意传递给单例对象的Context最好是Application Context。
- 《Android源码设计模式解析与实战》读书笔记(二)
- 《Android源码设计模式解析与实战》读书笔记(二)——单例模式
- 《Android源码设计模式解析与实战》读书笔记(二十)——适配器模式
- 《Android源码设计模式解析与实战》读书笔记(二十一)——装饰者模式
- 《Android源码设计模式解析与实战》读书笔记(二十二)——享元模式
- 《Android源码设计模式解析与实战》读书笔记(二十三)——外观模式
- 《Android源码设计模式解析与实战》读书笔记(二十四)——桥接模式
- 【读书笔记】Android源码设计模式解析与实战(二)——单例模式
- 《Android源码设计模式解析与实战》读书笔记(一)
- 《Android源码设计模式解析与实战》读书笔记(三)
- 《Android源码设计模式解析与实战》读书笔记(四)
- 《Android源码设计模式解析与实战》读书笔记(五)
- 《Android源码设计模式解析与实战》读书笔记(六)
- 《Android源码设计模式解析与实战》读书笔记(七)
- 《Android源码设计模式解析与实战》读书笔记(八)
- 《Android源码设计模式解析与实战》读书笔记(九)
- 《Android源码设计模式解析与实战》读书笔记(十)
- 《Android源码设计模式解析与实战》读书笔记(十一)
- Struts2运行流程分析
- 在eclipse中将android项目生成apk并且给apk签名
- 09_Java 文档注释
- struts2中"input"表示什么含义?
- zzulioj 1815: easy problem (暴力加技巧)
- 《Android源码设计模式解析与实战》读书笔记(二)
- 一步一步写二叉平衡树(AVL树)
- Ubuntu Nginx 通过包管理器安装与卸载
- 10_Java 实例
- MySQL5.6新特性之GTID、多线程复制 - 不知为何
- 第一篇博客
- zzulioj 1816: 矩形 (技巧)
- maven创建多bundle的springMVC框架模块简单概述(补充中)
- [leetcode 303] Range Sum Query - Immutable