美文网首页
Looper对象是如何与线程对应的

Looper对象是如何与线程对应的

作者: 超级绿茶 | 来源:发表于2019-11-26 13:54 被阅读0次

在解释Handler原理时有个一个现象;每一个线程都要有自己专属的Looper对象,如果没有的话在创建Handler对象时会报错。参见:可以在子线程实例化Handler对象吗

那么线程Thread是怎么和Loope对应上的?尤其是多个线程和多个Looper的情况下是怎么实现的?这就是涉及到一个叫ThreadLocal的类,ThreadLocal类其实就是一个map集合类型的封装类,可以为不同的线程保留这个线程的本地变量。它在Looper中的用法也很简单,ThreadLocal被定义成静态变量,并且有两个与之对应的静态方法prepare和myLooper用于操作, 这里看一下源码:

// sThreadLocal.get() will return null unless you've called prepare().
@UnsupportedAppUsage
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

private static void prepare(boolean quitAllowed) {
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    sThreadLocal.set(new Looper(quitAllowed));
}

/**
* Return the Looper object associated with the current thread.  Returns
* null if the calling thread is not associated with a Looper.
*/
public static @Nullable Looper myLooper() {
    return sThreadLocal.get();
}

prepare方法会先从sThreadLocal里获取Looper对象,如果为空则创建Looper并保存时sThreadLocal。而myLooper则直接获取Looper对象,如果获取不得话就返回空,ThreadLocal在Looper里的作用就这些。但问题是ThreadLocal是怎么知道哪一个Looper属于哪个Thread的?我们继续查看ThreadLocal的set方法:

public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}

前面说过ThreadLocal的本质是一个map集合的封闭类,set方法需要传一个变量作为map的value值,value是一个泛型,在Looper中自然是传入一个被实例化的Looper对象,然后再以当前的线程为key值进行保存或取出。所以说到这里应该就能明白多个Looper对象是怎么和多个Thread对象产生联系的吧!

最后说一下ThreadLocalMap这个类,通过名称我们可以认为它是一个map集合型的类,用法也和其它的map集合相似。但仔细看源码后我们发现ThreadLocalMap类并不简单;首先它是ThreadLocal的静态内部类,内部维护着一个类型为Entry的数组,对于ThreadLocalMap的操作就是围绕着这个数组展开的。而这个Entry居然也是一个静态内部类而且是弱引用以便于GC回收,Entry可以容纳一个Key和一个value值。定义如下:

static class Entry extends WeakReference<ThreadLocal<?>> {
    /** The value associated with this ThreadLocal. */
    Object value;

    Entry(ThreadLocal<?> k, Object v) {
        super(k);
        value = v;
    }
}

ThreaLocalMap的构造方法和相关的属性如下:(有省略)

private Entry[] table;

private int size = 0;

ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
    table = new Entry[INITIAL_CAPACITY];
    int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
    table[i] = new Entry(firstKey, firstValue);
    size = 1;
    setThreshold(INITIAL_CAPACITY);
}

从构造器可以看出ThreadLocalMap对外提供的是map集合式的操作,但内部却是通过数组遍历的方法来实现的。

点击链接加入群聊【口袋里的安卓】:861401732
或关注微信公众号:

相关文章

  • Looper对象是如何与线程对应的

    在解释Handler原理时有个一个现象;每一个线程都要有自己专属的Looper对象,如果没有的话在创建Handle...

  • Handler机制

    handler中的looper如何与当前线程绑定 handler实例化的时候会构造对应该handler的loope...

  • 【安卓学习笔记】Handler消息传递

    笔记要点 Handler主要用于非UI线程中对UI进行更新; 每个线程中都会对应一个Looper对象,Looper...

  • 2019-06-03 面试总结

    Android基础: Handler的机制 线程切换的具体原理?Handler和Looper的对应关系?如何在...

  • ThreadLocal

    我们在研究Handler曾经说过,线程与Looper的对应关系是通过ThreadLocal来实现的,那么Threa...

  • 日常小笔记(二)

    12、Hander持有对当前线程消息队列MessageQueue和消息循环Looper的引用 13、子线程与子线程...

  • 2020-02-19

    Handler机制中,由于一个Looper对应着一个线程,所以将Looper存进ThreadLocal最合适不过了...

  • 消息处理机制Looper,Handler,Message

    Looper Looper 线程 Looper.prepare() 每个线程中的Looperduixiang 其实...

  • 源码笔记01-Handler

    总结 其中绿色的部分与蓝色可能在一个线程,也可能不在一个线程 初始化handler时,指定了对应的Looper以及...

  • 线程、Handler、Looper之间关系

    1. 一个线程能否创建多个Handler,Handler跟Looper之间的对应关系? 一个线程,Handler跟...

网友评论

      本文标题:Looper对象是如何与线程对应的

      本文链接:https://www.haomeiwen.com/subject/zquewctx.html