单例模式的定义:
确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
实现单例模式的关键点:
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 objMap = new HashMap();
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 IActivityManagerSingleton =
new Singleton() {
@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 {
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
@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
new HashMap
//Service容器
private static final HashMap> SYSTEM_SERVICE_FETCHERS =
new HashMap>();
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 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 implements ServiceFetcher {
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
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
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 void registerService(String serviceName, Class serviceClass,
ServiceFetcher serviceFetcher) {
SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
}
//静态代码块,第一次加载该类的时候执行(只执行一次,保证实例的唯一性)
static {
registerService(Context.ACCESSIBILITY_SERVICE, AccessibilityManager.class,
new CachedServiceFetcher() {
@Override
public AccessibilityManager createService(ContextImpl ctx) {
return AccessibilityManager.getInstance(ctx);
}});
registerService(Context.CAPTIONING_SERVICE, CaptioningManager.class,
new CachedServiceFetcher() {
@Override
public CaptioningManager createService(ContextImpl ctx) {
return new CaptioningManager(ctx);
}});
registerService(Context.ACCOUNT_SERVICE, AccountManager.class,
new CachedServiceFetcher() {
@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() {
@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容器的单例模式实现方式,系统核心服务以单例形式存在,减少了资源消耗。
参考书籍:<