单列对象的类必须保证一个实例存在,而且自行实例化并向整个系统提供这个实例
使用场景:确保某个类有且只有一个对象的场景,避免产生多个对象消耗过多的资源,或者某种类型的对象只应该有且只有一个,如访问数据库
使用单列模式的关键点:
(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 HashMaphashMap = 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)方法,我们继续看