什么是单例设计模式?
单例模式是Java26种设计模式中的一种,日常开发中是非常常见的,其最大的特点是,帮助应用在运行某一个类时只会存在一个实例。
使用单例模式的意义
减少对象的创建,降低内存占用,提高代码的整洁性。举个例子,像有时候会创建一个数据管理类DataManager,里面会有缓存管理、线程池处理等一系列工具的实现,直接操作多类Data,这种一般就没有理由创建多个实例,也就是单例模式的使用场景。
单例模式的实现方式
-
懒汉式加载
顾名思义,懒汉由于真的太懒了,只有真的迫不得已需要使用到该对象时,才会去创建。一般较常见的写法如下2种:
- Double Check Lock(DCL)单例模式
public class DCLSingleton {
private static volatile DCLSingleton sInstance = null;
public static DCLSingleton getInstance(){
if(sInstance == null){
synchronized (DCLSingleton.class){
sInstance = new DCLSingleton();
}
}
return sInstance;
}
private DCLSingleton(){
// do something...
}
}
这种写法需要考虑多线程情况,所以增加volatile及synchronized很大程度保证程序的正确性,但会牺牲一点的性能,除非你的代码涉及密集的高并发使用场景,否则这种写法一般都能满足需求。
- 静态内部类单例模式
public class InnerClassSingleton {
private static InnerClassSingleton sInstance = null;
public static InnerClassSingleton getInstance(){
return LazyHolder.INSTANCE;
}
private InnerClassSingleton(){
// do something...
}
public static class LazyHolder{
public static final InnerClassSingleton INSTANCE = new InnerClassSingleton();
}
}
上述的写法在LazyHolder在虚拟机加载时保证InnerClassSingleton的仅会存在一个对象,囊括了DCL写法的优点,属于当下比较优秀的一种实现。
-
饿汉式加载
饿汉式属于从类加载的时候,就会把类实例创建完成,这种方式无需考虑多线程情况。常见的写法有以下2种:
- 饿汉式经典
public class HungrySingleton {
private static final HungrySingleton sInstance = new HungrySingleton();
public static HungrySingleton getInstance(){
return sInstance;
}
private HungrySingleton(){
// do somethine...
}
}
HungrySinleton类在加载时直接创建唯一实例,把创建优先级提前,使用到实例时直接getInstance获取返回。
- 枚举式单例
public enum EnumSingleton {
INSTANCE;
private EnumSingleton(){
// do something...
}
}
枚举的单例写法优势在于比较简单,天生枚举实例就是线程安全的。总体而言也不失为一个较好的实现方式。
总结
- 单例模式的使用场景非常广泛,包括大多数的需要被频繁创建、使用的实例。
- 单例模式下一个类只会存在一个实例,减少内存开支,提高系统性能,避免对资源的多重占用,仅在一个对象的入口操作
- 在Android上使用需要注意内存泄露问题,因为单例模式中的实例生命周期与应用一致,若内部有占用如context之类生命周期较短的对象,需要及时退出,避免发生内存泄露。