一个Thread中只有一个Looper源码解释


Thread中为什么只有一个Looper呢

首先看到Looper中的的prepare方法

public static void prepare() {
        prepare(true);
    }

    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));
    }

sThreadLocal是ThraedLocal类的.

ThreadLocal并不是一个Thread,而是Thread的局部变量,当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本.
先看sThreadLocal.get()方法
    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null)
                return (T)e.value;
        }
        return setInitialValue();
    }
可以看到在get()方法中 先是获得了当前线程的对象, 同一个ThreadLocal对象在不同的线程中执行get方法获得的Thread对象是不同的,然后由getMap(t)获得的ThreadLocalMap方法也是不同的,接下来判断这个map存不存在。如果不存在就创建一个 ,一般是存在的,那么就用ThreadLocal对象从这个Map中拿到对应的 Entry 对象 ,然后将这个Entry对象中的value取出来, 这个Entry对象就像一个键值对,键就是ThreadLocal对象 值就是你放进去的Object,这个方法最终返回的e.value就是我们的looper.
在这儿提一下ThreadLocalMap 它是在ThreadLocal中定义的,但是是Thread的一个成员变量, ThreadLocal想获得当前线程的ThreadLocalMap对象,得先获得当前线程的对象, 这个ThreadLocalMap中还封装了一个Entry[]数组,
接着再来看map.getEntry(this)方法,看看ThreadLocalMap是怎么根据ThreadLocal对象获得value的
        private Entry getEntry(ThreadLocal key) {
            int i = key.threadLocalHashCode & (table.length - 1);
            Entry e = table[i];
            if (e != null && e.get() == key)
                return e;
            else
                return getEntryAfterMiss(key, i, e);
        }
可以看到 先是根据传进来的ThreadLocal对象获得一个 threadLocalHashCode值然后再&上(&是双方只要有一个0结果就为0),再将获得的I值作为索引 从ThreadLocalMap的成员变量Entry[]中获得对应的Entry 。
threadLocalHashCode是什么呢
private final int threadLocalHashCode = nextHashCode();
private static synchronized int nextHashCode() {  
    int h = nextHashCode;  
    nextHashCode = h + HASH_INCREMENT;  
    return h;  
}  
,搜索一下,可以看到就是将ThreadLocal类的下一个hashCode值即nextHashCode的值赋给实例的threadLocalHashCode,然后将nextHashCode的值增加给HASH_INCREMENT这个值,因此ThreadLocal实例的变量只有这个threadLocalHashCode 而且是final的 用来区分不同的ThreadLocal实例
这下ThreadLocal的get方法就搞定了,
接下来看下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);
    }
和get方法很类似,点击map.set(this,value)进去
        private void set(ThreadLocal key, Object value) {

            // We don't use a fast path as with get() because it is at
            // least as common to use set() to create new entries as
            // it is to replace existing ones, in which case, a fast
            // path would fail more often than not.

            Entry[] tab = table;
            int len = tab.length;
            int i = key.threadLocalHashCode & (len-1);

            for (Entry e = tab[i];
                 e != null;
                 e = tab[i = nextIndex(i, len)]) {
                ThreadLocal k = e.get();

                if (k == key) {
                    e.value = value;
                    return;
                }

                if (k == null) {
                    replaceStaleEntry(key, value, i);
                    return;
                }
            }

            tab[i] = new Entry(key, value);
            int sz = ++size;
            if (!cleanSomeSlots(i, sz) && sz >= threshold)
                rehash();
        }
可以看到,还是根据穿进去的ThreadLocal对象获得的索应获得Entry[]数组中相应的Entry对象, 然后将传进来的参数
赋给Entry.value, 这个传进来的参数在我们这儿也就是Looper对象,Looper对象就被存在这里了,我下面画了一个图方便大家看




评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值