单列对象的类必须保证一个实例存在,而且自行实例化并向整个系统提供这个实例
使用场景:确保某个类有且只有一个对象的场景,避免产生多个对象消耗过多的资源,或者某种类型的对象只应该有且只有一个,如访问数据库
使用单列模式的关键点:
(1)构造函数不对外开放,一般为private
(2)通过一个静态方法或者枚举返回单列对象
(3)确保单列对象有且只有一个,尤其多线程环境下
(4)确保单列对象在反序列化时不会重新构建对象
(一)饿汉式
public class IOUtil {
private static final IOUtil INSTANCE = new IOUtil();
private IOUtil(){
}
public static IOUtil getInstance(){
return INSTANCE;
}
}
(二)懒汉式
是声明一个静态对象,并且在用户第一次调用getInstance时初始化
public class IOUtil {
private static IOUtil INSTANCE = null;
private IOUtil(){
}
public static synchronized IOUtil getInstance(){
if (INSTANCE == null){
INSTANCE = new IOUtil();
}
return INSTANCE;
}
}
getInstance()方法中添加一个synchronized关键字,也就是getInstance的一个同步方法,者就是在多线程情况下保证单列对象唯一性的手段。但是,每次使用getInstance时都会synchronized同步,会造成不必要的同步开销,所以建议不使用多线程时,不使用该关键字
(三)DCL实现单列
DCL实现单例模式的优点是既能在需要时才初始化单列,又能保证线程安全,且单列对象初始化后调用getInstance不进行同步锁
public class IOUtil {
private static IOUtil INSTANCE = null ;
private IOUtil(){
}
public static IOUtil getInstance(){
if (INSTANCE == null){
synchronized (IOUtil.class){
if (INSTANCE == null){
INSTANCE = new IOUtil();
}
}
}
return INSTANCE;
}
}
优点:资源利用率高
缺点:第一次加载时反应慢
(四)静态内部类单列模式
DCL虽然在一定程度上解决了消耗资源,多余的同步,线程安全等问题,但是,它还是在某些情况下出现失效的问题,不赞成使用
public class IOUtil {
public static IOUtil getInstance(){
return SingleHolder.INSTANCE;
}
private static class SingleHolder{
public static final IOUtil INSTANCE = new IOUtil();
}
}
当第一次加载IOutil类时并不会初始化INSTANCE ,只有在第一次调用getInstance时才会导致INSTANCE被初始化,这种方式不仅保证线程安全,也能保证单例对象的唯一性,推荐使用。
(五)使用容器实现单例模式
public class IOUtil {
private static HashMap<String,Object> hashMap = new HashMap<>();
public static void registerService(String key,Object object){
if (!hashMap.containsKey(key)){
hashMap.put(key,object);
}
}
public static Object getService(String key){
return hashMap.get(key);
}
}
Android源码中的单列模式
在Android系统中,我们经常会通过Context获取系统级别的服务,如WindowManagerService ,ActivityManagerService等。更常用的是LayoutInflater的类,LayoutInflater较为常见的地方是在ListView的getView方法中
View view = LayoutInflater.from(mContext).inflate(layoutId,null);
可以看到的form(Context)函数内部调用的是Context类的getSystemService(String key)方法,我们继续看