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()方法
可以看到在get()方法中 先是获得了当前线程的对象, 同一个ThreadLocal对象在不同的线程中执行get方法获得的Thread对象是不同的,然后由getMap(t)获得的ThreadLocalMap方法也是不同的,接下来判断这个map存不存在。如果不存在就创建一个 ,一般是存在的,那么就用ThreadLocal对象从这个Map中拿到对应的 Entry 对象 ,然后将这个Entry对象中的value取出来, 这个Entry对象就像一个键值对,键就是ThreadLocal对象 值就是你放进去的Object,这个方法最终返回的e.value就是我们的looper.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(); }
在这儿提一下ThreadLocalMap 它是在ThreadLocal中定义的,但是是Thread的一个成员变量, ThreadLocal想获得当前线程的ThreadLocalMap对象,得先获得当前线程的对象, 这个ThreadLocalMap中还封装了一个Entry[]数组,
接着再来看map.getEntry(this)方法,看看ThreadLocalMap是怎么根据ThreadLocal对象获得value的
可以看到 先是根据传进来的ThreadLocal对象获得一个 threadLocalHashCode值然后再&上(&是双方只要有一个0结果就为0),再将获得的I值作为索引 从ThreadLocalMap的成员变量Entry[]中获得对应的Entry 。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); }
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方法
和get方法很类似,点击map.set(this,value)进去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对象获得的索应获得Entry[]数组中相应的Entry对象, 然后将传进来的参数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(); }
赋给Entry.value, 这个传进来的参数在我们这儿也就是Looper对象,Looper对象就被存在这里了,我下面画了一个图方便大家看