野风技术札记 2019-06-28
在Android-27中查看源码:
在Looper源码中,我们看到通过ThreadLocal的set方法来保存Looper,通过get方法来取出Looper。下来我们来看ThreadLocal中的set/get方法。
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); } ThreadLocalMap getMap(Thread t) { return t.threadLocals; } void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); } public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); } private T setInitialValue() { T value = initialValue(); Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); return value; }
从中可以看到真正保存的是在Thread.threadLocals中,接着看看ThreadLocalMap的源码。
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); } 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(); }
在ThreadLcoalMap中创建了数组,利用数组来保存Entry,Entry中保存了ThreadLocal和值。数组的初始长度为16,最多可保存length/2一旦超过就进行扩容(增加一倍)。
所以ThreaLocal的作用是用来实现线程内部的数据共享,其实现原理是利用线程内部的ThreaLocalMap来保存数据。而ThreadLocalMap内部利用数组来保存ThreadLocal和值的,数组的索引就是ThreadLocal的哈希值&(数组的长度-1)。