framework當中的單例模式

最近看了一些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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章