最近看了一些framework的代码,发现里面用到了一些单例模式,挺有意思的,我们在自己的项目当中也可以借鉴。
1.进程内的单例
首先是我们最熟悉也最常用的,就是进程内的单例
Singleton是一个抽象类,里面有一个抽象函数create,我们只需要继承Singleton,然后实现其抽象函数就可以实现单例模式了。这样可以帮我们节省很多的代码。
public abstract class Singleton<T> {
private volatile static T instance;
public abstract T create();
public final T get() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = create();
}
}
}
return instance;
}
}
2.线程内的单例
线程内的单例其实是通过ThreadLocal实现的,在屏幕刷新机制当中需要使用的Choreographer类,就实现了线程内的单例。
如下代码所示,sThreadInstance是一个ThreadLocal变量,并重写了initialValue方法,当在一个线程内有值,则直接返回,否则就会调用initialValue方法创建一个新的对象。
private static final ThreadLocal<Choreographer> sThreadInstance =
new ThreadLocal<Choreographer>() {
@Override
protected Choreographer initialValue() {
Looper looper = Looper.myLooper();
if (looper == null) {
throw new IllegalStateException("The current thread must have a looper!");
}
return new Choreographer(looper, VSYNC_SOURCE_APP);
}
};
public static Choreographer getInstance() {
return sThreadInstance.get();
}
同样我们也可以仿照Singleton的方式,实现一个抽象类
public abstract class ThreadSingleton<T> {
private ThreadLocal<T> instance = new ThreadLocal<T>() {
@Override
protected T initialValue() {
return create();
}
};
public abstract T create();
public final T get() {
return instance.get();
}
}
3.进程间的单例
其实ServiceManager就实现了进程间的单例。
首先我们来看下,ServiceManager创建的时候是如何保证系统只有一个ServiceManager进程的。
以下是service_manager.c的main函数源码。
在注释1处打开了binder驱动,在注释2处将自己在binder驱动当中进行注册,也就是告诉binder驱动,系统当中已经有了ServiceManager进程了,如果系统再启动一个ServiceManager进程,再注册的时候,就会报错,第二个ServiceManager进程就会启动失败。
这样就保证了系统当中只有一个ServiceManager进程。
int main(int argc, char** argv)
{
struct binder_state *bs;
union selinux_callback cb;
char *driver;
if (argc > 1) {
driver = argv[1];
} else {
driver = "/dev/binder";
}
//1.打开binder驱动
bs = binder_open(driver, 128*1024);
if (!bs) {
#ifdef VENDORSERVICEMANAGER
ALOGW("failed to open binder driver %s\n", driver);
while (true) {
sleep(UINT_MAX);
}
#else
ALOGE("failed to open binder driver %s\n", driver);
#endif
return -1;
}
//2.将自己注册到binder驱动当中
if (binder_become_context_manager(bs)) {
ALOGE("cannot become context manager (%s)\n", strerror(errno));
return -1;
}
......
}
然后我们来看下,是如何来获取到ServiceMananger服务的
可以看到在ServiceManager当中通过getContextObject来获取服务,最终会调到ProcesState当中的getContextObject,对所有的进程来说ServiceManager的句柄均为0,这样就获取到了ServiceManager服务。
//ServiceManager.java
private static IServiceManager getIServiceManager() {
if (sServiceManager != null) {
return sServiceManager;
}
// Find the service manager
sServiceManager = ServiceManagerNative
.asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
return sServiceManager;
}
//ProcessState.cpp
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
return getStrongProxyForHandle(0);
}