当一个对象需要消耗很多资源的时候,就要考虑使用单例模式。
单例模式的关键点
(1)一个私有的构造函数。
(2)通过枚举或者静态方法返回实例。
(3)确保对象只有一个。
(4)确保反序列化的时候不会重新构建。
单例模式的具体实现
饿汉模式:在创建的时候就进行实例化。
懒汉模式:在需要的时候才进行实例化。
DCL模式:
public class Singleton {
private static Singleton sInstance = null;
private Singleton(){
}
public void doSomething(){
System.out.println("do sth");
}
public static Singleton getInstance(){
if (sInstance == null){
synchronized (Singleton.class){
if (sInstance == null){
sInstance = new Singleton();
}
}
}
return sInstance;
}
}
首先保存了一个静态的实例,并在getInstance才进行初始化。在getInstance中进行了两次实例是否存在的判断,首先第一层是为了在单例已经存在的情况下不去进行同步操作,提高效率。第二层的判断是因为在JVM中,有可能是先给实例引用之后再执行构造函数,这样就会出错,第二重判断就能保证在不会出现这种情况,一定是先执行构造函数再提供引用。
静态内部类单例模式
public class Singleton {
private Singleton(){};
public static Singleton getInstance(){
return SingletonHolder.sInstance;
}
private static class SingletonHolder {
private static final Singleton sInstance = new Singleton();
}
}
首先单例模式不变的私有构造函数,和静态的公有获取方法。这里返回的单例是被一个静态的内部类持有的。
枚举类型
以上的单例方法在反序列化的时候仍然会重新创建,而枚举类型即使在反序列化的时候也不会重复创建。
使用容器的方法实现单例
public class SingletonManager {
private static HashMap<String,Integer> services = new HashMap<>();
private SingletonManager(){};
public static void registerService (String key,Integer value){
if (!services.containsKey(key)){
services.put(key,value);
}
}
public static Object getInstance (String key){
return services.get(key);
}
}
SingletonManager中维护一个静态的容器,利用容器的性质实现单例。
Android中利用单例模式实现服务
首先from(Context)调用的是getSystemService(String key)方法,这里传入的Context的具体实现类ContextImpl,首先
Avtivity的入口是ActvityThread的main函数,main函数中创建了一个ActivityThread对象之后,调用attach函数,参数为fasle,表示是非系统应用,这个对象通过Binder机制和ActivityManager通信,最后调用handleLaunchActivity,在这里面获取了创建了Context对象,并进行了设置。在虚拟机第一次加载ContextImpl时,注册类各种ServiceFetcher,其中包含了LayoutInflater Service,这些服务以键值对的形式存储杂一个HashMap中,用户只需要根据Key来获取到对应的ServiceFetcher,通过ServiceFetcher的getService获取到各种服务对象,这些服务对象会缓存到列表中,下次再取的时候直接从列表中获取。