单例模式的定义
确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例
单例模式的使用场景
确保某个类有且只有一个对象的场景,避免产生多个对象消耗过多的资源,或者某种类型的对象只应该有且只有一个。例如,创建一个对象需要消耗的资源过多,如要访问IO和数据库等资源,这时就要考虑使用单利模式。
单例模式UML类图
* 构造函数不对外开放,一般为Private。
* 通过一个静态方法或者枚举返回单例类对象。
* 确保单例类的对象有且只有一个,尤其是在多线程环境下。
* 确保单例类对象在反序列化时不会重新构建对象。
示例
- ###饿汉模式:是在声明静态对象时就已经初始化
public class Single {
private static final Single single=new Single();
private Single(){
}
public static Single getInstance(){
return single;
}
}
在声明时就初始化对象,保证了对象的唯一性。
* ###懒汉模式:是声明一个静态对象,并且在用户第一次调用getInstance时进行初始化。
public class Single {
private static Single single;
private Single() {
}
public static synchronized Single getInstance() {
if (single == null) {
single = new Single();
}
return single;
}
}
其中synchronized用于在多线程情况下保证单例对象唯一性。优点:在使用时才被实例化,节约了资源。缺点:第一次加载时需要实例化,反应慢,每次调用getInstance都进行同步,造成没必要的开销。一般不建议使用这种方式。
* ###Double Check Lock(DCL)实现单例
public class Single {
private static Single single = null;
private Single() {
}
public static Single getInstance() {
if (single == null) {
synchronized (Single.class) {
if (single == null) {
single = new Single();
}
}
}
return single;
}
}
优点:在需要时初始化单例,能够保证线程安全,对象初始化后调用getInstance不进行同步锁。缺点:第一次加载时反应较慢。是使用最多的单例实现方式。
* ###静态内部类单例模式
public class Single {
private Single() {
}
public static Single getInstance() {
return SingleHolder.single;
}
private static class SingleHolder {
private static final Single single = new Single();
}
}
第一次调用getInstance方法会导致虚拟机加载SingleHolder类,能够保证线程安全、单例对象的唯一性,延迟了单例的实例化,是推荐使用的单例模式实现方式。
优点
- 由于单例模式在内存中只有一个实例,减少了内存开支,特别是一个对象需要频繁的创建和销毁时,而且创建或销毁时性能又无法优化,单例模式的优势就非常明显。
- 减少了系统的性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他的依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后用永久驻留内存的方式来解决。
- 单例模式可以避免对资源的多重占用,例如一个写文件操作,由于只有一个实例存在内存中,避免对同一个资源文件的同时写操作。
- 单例模式可以在系统设置全局的访问点,优化和共享资源访问。例如,可以设计一个单例类,负责所有数据表的映射处理。
缺点
- 单例模式一般没有借口,扩展很困难,若要扩展,除了修改代码基本上没有第二种途径可以实现。
- 单例对象如果持有Context,那么很容易引发内训泄露,此时需要注意传递给单例对象的Context最好是Application Context。