单例模式的定义:
确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
实现单例模式的关键点:
1.构造函数不对外开放,一般为private。
2.通过一个静态方法或者枚举返回单例类对象。
3.确保单例类的对象有且只有一个,尤其是在多线程环境下。
4.确保单例类对象在反序列化时不会重新构建对象。
1.饿汉式 单例模式 (在声明的时候已经初始化了)
public class Singleton { private static final Singleton s = new Singleton(); private Singleton () { } public static Singleton getIntance() { return s; } }
2.懒汉式 单例模式
public class SingletonTwo { private static SingletonTwo singletonTwo; private SingletonTwo () { } public static synchronized SingletonTwo getInstance() { if (singletonTwo == null) { singletonTwo = new SingletonTwo(); } return singletonTwo; } }
上面通过添加 synchronized关键字,使得getInstance()是一个同步方法,保证多线程情况下单例对象的唯一性。
懒汉式优点:
1.单例只有在使用时才会被实例化,在一定程度上节约了资源。
缺点:
1.第一次加载时需要及时进行实例化,反应稍慢。
2.每次调用getIntance都进行同步,造成不必要的同步开销。
3.Double Check Lock(DCL) 实现单例
public class DoubleSingleInstance { private static DoubleSingleInstance sSingleInstance; private DoubleSingleInstance() { } public static DoubleSingleInstance getIntance() { if (sSingleInstance == null) { synchronized (DoubleSingleInstance.class) { if (sSingleInstance == null) { sSingleInstance = new DoubleSingleInstance(); } } } return sSingleInstance; } }
在getInstance()中对instance进行两次判空,第一层判空:避免不必要的同步。第二次判空:在instance为null的情况下创建实例。
/*****/
假设线程A执行到sInstance = new Singletion()语句,这里看起来是一句代码,但实际上不是一个原子操作。
最终
被编译成多条汇编指令:
1.给Singletom的实例分配内存;
2.调用Singleton()的构造函数,初始化成员字段;
3.将sInstance对象指向分配的内存空间(此时sInstance就不是null了)。
由于java编译器允许处理器乱序执行。(可能导致单例对象的某些字段没有初始化)
3.1在JDK1.5之后,SUN发现该问题,调整了JVM,具体化了volatile关键字。
所以在JDK1.5以及其之后,只需要将sInstance定义成private volatile static Singleton sInstance = null,就可以保证sInstance对象每次都是从主内存中读取。
4.静态内部类单例模式
DCL虽然在一定程度上解决了资源消耗、多余同步、线程安全等问题。
(但还是会存在 双重检查锁定(DCL)失效)
public class InnerSingleton { private InnerSingleton() { } public static InnerSingleton getInstance() { return SingletonHolder.sIntance; } /** * 静态内部类 */ private static class SingletonHolder{ private static final InnerSingleton sIntance = new InnerSingleton(); } }
使用静态内部类单例模式的优点:
第一次加载Singleton类时并不会初始化sIntance,只有第一次调用Singleton的getInstance方法才会导致sInstance被初始化。
第一次调用getInstance()方法会导致虚拟机加载SingletonHolder类。
优点:
保证线程安全。
保证单例对象的唯一性。
延迟单例的实例化。
5.枚举单例
public enum SingleEnum { INSTANCE; }
最重要的是默认枚举实例的创建是线程安全的,并且在任何情况下它都是一个单例。
在1~4种创建单例模式的方法中,在反序列化的情况下会重新创建对象。
我们知道通过序列化可以将一个单例的实例对象写到磁盘,然后再读回来,从而有效获取一个实例。
即使构造函数是私有的,反序列化依然可以通过特殊的途径去创建类的一个新的实例,相当于调用该类的构造函数。
反序列化操作提供了一个很特别的钩子函数,类中具有一个私有的readResolve()函数,这个函数可以让开发人员控制对象的反序列化。
public class SingletonSerializable implements Serializable{ private static final long serialVersionUID = 0L; private static final SingletonSerializable INSTANCE = new SingletonSerializable(); private SingletonSerializable() { } public static SingletonSerializable getInstance() { return INSTANCE; } private Object readResolve() throws ObjectStreamException{ return INSTANCE; } }
也就是在readResolve方法中将单例对象返回,而不是重新生成一个新对象。
对于枚举,并不存在这个问题,因为即使反序列化它也不会重新生成新的实例。
(1)可序列化类中的字段类型不是java的内置类型,那么该字段类型也需要实现Serializable接口。
(2)如果你调整了可序列化类的内部结构,例如新增、去除某个字段,但是没有修改serialVersionUID,那么会引发java.io.InvalidClassException 或者导致某个属性为0或者null,此时最好的方案是我们直接将serialVersionUID设置为0L,这样即使修改了内部结构,我们反序列化也不会抛出java.io.InvalidClassException ,只是那些新增的字段会为0或者null。
6.使用容器实现单例模式
public class SingletonManager { private static Map<String, Object> objMap = new HashMap<String, Object>(); private SingletonManager () { } public static void registerService(String key, Object instance) { if (!objMap.containsKey(key)) { objMap.put(key, instance); } } public static Object getService(String key) { return objMap.get(key); } }
在程序的初始,将多种单例类型注入到一个统一的管理类中,在使用时根据key获取对应类型的对象。
单例模式核心:
1.将构造函数私有化。
2.通过静态方法获取唯一的实例。
3.保证线程安全
4.防止反序列化导致重新生成实例对象等问题
//Android framework中大多使用静态内部类的方式实现单例。 private static final Singleton<IActivityManager> IActivityManagerSingleton = new Singleton<IActivityManager>() { @Override protected IActivityManager create() { final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE); final IActivityManager am = IActivityManager.Stub.asInterface(b); return am; } }; package android.util; /** * Singleton helper class for lazily initialization. * 用于延迟初始化的Singleton helper类。 * Modeled after frameworks/base/include/utils/Singleton.h * * @hide */ public abstract class Singleton<T> { private T mInstance; protected abstract T create(); public final T get() { synchronized (this) { if (mInstance == null) { mInstance = create(); } return mInstance; } } }
Android源码中的单例模式:
在android系统中,通过Context获取系统级别的服务,如WindowManagerService,ActivityManagerService等,常用是LayoutInflater,这些服务会在合适的时候以单例的形式注册在系统中, 这些服务会在合适的时候以单例的形式注册在系统中,在我们需要的时候通过Context的getSystemService(String name)获取。
#LayoutInflater /** * Obtains the LayoutInflater from the given context. */ public static LayoutInflater from(Context context) { LayoutInflater LayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); if (LayoutInflater == null) { throw new AssertionError("LayoutInflater not found."); } return LayoutInflater; }
#ContextImpl public class ContextImpl extends Context { ... ... ... ... } #ContextImpl @Override public Object getSystemService(String name) { return SystemServiceRegistry.getSystemService(this, name); } #ContextImpl @Override public Object getSystemService(String name) { return SystemServiceRegistry.getSystemService(this, name); }
每一个ContextImpl对象都会初始化一个mServiceCache数组,这个数组的大小就是系统服务的数量。
#ContextImpl // The system service cache for the system services that are cached per-ContextImpl. final Object[] mServiceCache = SystemServiceRegistry.createServiceCache();
通过Context对象获取系统服务对象。
/** *管理所有系统服务 ,SystemServiceRegistry 起到一个工具类的作用,其构造方法私有。 * Manages all of the system services that can be returned by {@link Context#getSystemService}. * Used by {@link ContextImpl}. * @hide */ public final class SystemServiceRegistry { ... ... }
SystemServiceRegistry首次加载。
以LayoutInflater注册为例:registerService方法注册LayoutInflater时,需要参数Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class,以及CachedServiceFetcher对象。
registerService(Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class,
new CachedServiceFetcher<LayoutInflater>() {
@Override
public LayoutInflater createService(ContextImpl ctx) {
return new PhoneLayoutInflater(ctx.getOuterContext());
}});
/**
* Gets the name of the system-level service that is represented by the specified class.
*获取由指定类表示的系统级服务的名称。
*/
public static String getSystemServiceName(Class<?> serviceClass) {
return SYSTEM_SERVICE_NAMES.get(serviceClass);
}
// Service registry information.
//静态初始化完成后,此信息永远不会更改
// This information is never changed once static initialization has completed.
private static final HashMap<Class<?>, String> SYSTEM_SERVICE_NAMES =
new HashMap<Class<?>, String>();
//Service容器 private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS = new HashMap<String, ServiceFetcher<?>>();
private static int sServiceCacheSize;
/** * 从给定的上下文获取系统服务。 * Gets a system service from a given context. */ //根据key获取对应的服务 public static Object getSystemService(ContextImpl ctx, String name) { //根据name获取对应的服务 ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name); return fetcher != null ? fetcher.getService(ctx) : null; }
/**
*提取服务的类的基本接口。这些对象只能在静态初始化期间创建。
* Base interface for classes that fetch services.
* These objects must only be created during static initialization.
* (竟然还可以是abstract 的接口)
*/
public static abstract interface ServiceFetcher<T> {
T getService(ContextImpl ctx);
}
/** * Override this class when the system service constructor needs a * ContextImpl and should be cached and retained by that context. * 当系统服务构造函数需要ContextImpl时覆盖此类,并且应该由该上下文进行缓存和保留。 */ public static abstract class CachedServiceFetcher<T> implements ServiceFetcher<T> { private final int mCacheIndex; public CachedServiceFetcher() { mCacheIndex = sServiceCacheSize++; } // 获取系统服务 @Override @SuppressWarnings("unchecked") public final T getService(ContextImpl ctx) { final Object[] cache = ctx.mServiceCache;//获取Service缓存 synchronized (cache) { // Fetch or create the service. Object service = cache[mCacheIndex]; if (service == null) { try { service = createService(ctx); cache[mCacheIndex] = service; } catch (ServiceNotFoundException e) { onServiceNotFound(e); } } return (T)service; } } //子类覆写该方法以创建服务对象 public abstract T createService(ContextImpl ctx) throws ServiceNotFoundException; }
/**
* Override this class when the system service does not need a ContextImpl
* and should be cached and retained process-wide.
*/
static abstract class StaticServiceFetcher<T> implements ServiceFetcher<T> {
private T mCachedInstance;
@Override
public final T getService(ContextImpl ctx) {
synchronized (StaticServiceFetcher.this) {
if (mCachedInstance == null) {
try {
mCachedInstance = createService();
} catch (ServiceNotFoundException e) {
onServiceNotFound(e);
}
}
return mCachedInstance;
}
}
public abstract T createService() throws ServiceNotFoundException;
}
/**
* Like StaticServiceFetcher, creates only one instance of the service per application, but when
* creating the service for the first time, passes it the application context of the creating
* application.
*
* TODO: Delete this once its only user (ConnectivityManager) is known to work well in the
* case where multiple application components each have their own ConnectivityManager object.
*/
static abstract class StaticApplicationContextServiceFetcher<T> implements ServiceFetcher<T> {
private T mCachedInstance;
@Override
public final T getService(ContextImpl ctx) {
synchronized (StaticApplicationContextServiceFetcher.this) {
if (mCachedInstance == null) {
Context appContext = ctx.getApplicationContext();
// If the application context is null, we're either in the system process or
// it's the application context very early in app initialization. In both these
// cases, the passed-in ContextImpl will not be freed, so it's safe to pass it
// to the service. http://b/27532714 .
try {
mCachedInstance = createService(appContext != null ? appContext : ctx);
} catch (ServiceNotFoundException e) {
onServiceNotFound(e);
}
}
return mCachedInstance;
}
}
public abstract T createService(Context applicationContext) throws ServiceNotFoundException;
}
/** * Statically registers a system service with the context. * This method must be called during static initialization only. * 用上下文静态注册系统服务。 * 该方法只能在静态初始化期间调用。 */ private static <T> void registerService(String serviceName, Class<T> serviceClass, ServiceFetcher<T> serviceFetcher) { SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName); SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher); }
//静态代码块,第一次加载该类的时候执行(只执行一次,保证实例的唯一性)
static { registerService(Context.ACCESSIBILITY_SERVICE, AccessibilityManager.class, new CachedServiceFetcher<AccessibilityManager>() { @Override public AccessibilityManager createService(ContextImpl ctx) { return AccessibilityManager.getInstance(ctx); }}); registerService(Context.CAPTIONING_SERVICE, CaptioningManager.class, new CachedServiceFetcher<CaptioningManager>() { @Override public CaptioningManager createService(ContextImpl ctx) { return new CaptioningManager(ctx); }}); registerService(Context.ACCOUNT_SERVICE, AccountManager.class, new CachedServiceFetcher<AccountManager>() { @Override public AccountManager createService(ContextImpl ctx) throws ServiceNotFoundException { IBinder b = ServiceManager.getServiceOrThrow(Context.ACCOUNT_SERVICE); IAccountManager service = IAccountManager.Stub.asInterface(b); return new AccountManager(ctx, service); }}); registerService(Context.ACTIVITY_SERVICE, ActivityManager.class, new CachedServiceFetcher<ActivityManager>() { @Override public ActivityManager createService(ContextImpl ctx) { return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler()); }}); ... ... }
从ContextImpl类的部分代码可以看到,在虚拟机第一次加载该类的时候会注册各种ServiceFatcher,其中就包含了LayoutInflater Service。
将这些服务以键值对的形式存储在一个HashMap中,用户使用时只需要根据key来获取对应的ServiceFetcher,然后通过ServiceFetcher对象的getService方法来获取具体的服务对象。
当第一次获取是,会调用ServiceFetcher的createService方法创建服务对象,然后将该对象缓存到一个列表中,下次再取时直接从缓存中获取,避免重复创建对象,从而达到单例的效果。
通过HashMap容器的单例模式实现方式,系统核心服务以单例形式存在,减少了资源消耗。