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);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值