最近看了一些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);
}