1、定义
单例模式属于创建型模式,确保一个类只有一个实例,并提供一个全局的访问接口。
2、使用场景
在开发工程中,有些对象我们只需要一个:线程池、缓存、硬件设备等, 创建多个实例则会造成结果的不一致和资源的过多消耗。
3、UML类图
4、经典的实现方式
1、懒汉模式
/**
* 懒汉模式
*/
public class SingleTon01 {
private static SingleTon01 instance;
private SingleTon01() {
}
public static synchronized SingleTon01 getInstance() {
if (instance == null) {
instance = new SingleTon01();
}
return instance;
}
}
懒汉模式在使用的时候才进行实例化,在一定程度上节约了资源,但是在每次调用getInstance()都进行了同步,造成不必要的同步。
2、Double Check Lock(DCL)模式
/**
* Double Check Lock(DCL)双锁检测
*/
public class SingleTon02 {
private volatile static SingleTon02 instance;
/**
* 构造方法私有化,不允许外部创建对象
*/
private SingleTon02() {
}
public static SingleTon02 getInstance() {
if (instance == null) {//第一次判空避免不必要的同步
synchronized (SingleTon02.class) {
if (instance == null) {//第二次判空为了在null的情况下创建实例
instance = new SingleTon02();
}
}
}
return instance;
}
}
DCL是使用最多的一种实现单例的方式,但在《Java并发编程实战》中提到这是一种"糟糕"的优化,在java1.5以前的版本中并没有真正解决线程同步问题,在1.5版本以后可以加上volatile3、静态类部类模式
/**
* 静态类部类模式
*/
public class SingleTon03 {
private SingleTon03() {
}
private static class SingletonHolder {
private static final SingleTon03 instance = new SingleTon03();
}
public static SingleTon03 getInstance() {
return SingletonHolder.instance;
}
}
这种方式不仅能够保证线程安全,同时也能够保证单例对象的唯一性,延迟单例对象的实例化。4、枚举实现单例
/**
* 枚举单例
*/
public enum SingleTon04 {
INSTANCE;
}
枚举对象的创建是现成安全的,并且也是唯一的。5、利用容器实现单例
/**
* 利用容器实现单例
*/
public class SingleTon05 {
private static Map<String, Object> objMap = new HashMap<>();
private SingleTon05() {}
public void addObj(String key, Object instance) {
if (!objMap.containsKey(key)) {
objMap.put(key, instance);
}
}
public static Object getObj(String key) {
return objMap.get(key);
}
}
我们可以通过这种方式管理多种类型的管理,如对activity的管理。
5、总结
优点:1、全局只有一个实例,减小了系统性能开销。
缺点:1、扩展困难,只能通过修改代码的方式进行扩展。
2、如果单例持有Context对象,容易造成内存泄漏问题,一般传递Application对象。
代码:https://gitee.com/os2chen/DesignPattern
参考:《Head First Design》、《Android源码设计模式解析与实战》