- 目录
- Handler、Looper、MessageQueue源码解析——Handler
- Handler、Looper、MessageQueue源码解析——Looper
- Handler、Looper、MessageQueue源码解析——ThreadLocal
- Handler、Looper、MessageQueue源码解析——MessageQueue
ThreadLocal
我们在上一节Looper中在myLooper()中提到可以通过sThreadLocal.get()方法可以得到当前线程的Looper对象,通过ThreadLocal的get()和set()方法,我们可以知道它是以key-value的方式储存变量,所以我们大概可以猜到它的内部实现是一个Map。接下来就来看看它的内部实现。
ThreadLocal有以下几个比较重要的方法:
- public T get()
- public void set(T value)
- protected T initialValue()
我们依次来看一下:
public T get() {
//获取当前Thread对象
Thread t = Thread.currentThread();
//通过当前Thread对象获得ThreadLocalMap
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
return setInitialValue();
}```
果不其然,Map来了,通过当前Thread对象获得一个ThreadLocalMap。ThreadLocalMap是ThreadLocal的一个内部类。
``` java
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}```
threadLocals是Thread的一个成员变量,所以getMap就是从获得Thread对应的ThreadLocalMap对象。
那么ThreadLocalMap是个什么东西呢?
```java
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal> {
Entry(ThreadLocal k, Object v) {
super(k);
value = v;
}
}
private static final int INITIAL_CAPACITY = 16;
private Entry[] table;
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 ThreadLocalMap(ThreadLocalMap parentMap) {
Entry[] parentTable = parentMap.table;
int len = parentTable.length;
setThreshold(len);
table = new Entry[len];
for (int j = 0; j < len; j++) {
Entry e = parentTable[j];
if (e != null) {
ThreadLocal key = e.get();
if (key != null) {
Object value = key.childValue(e.value);
Entry c = new Entry(key, value);
int h = key.threadLocalHashCode & (len - 1);
while (table[h] != null)
h = nextIndex(h, len);
table[h] = c;
size++;
}
}
}
}
private Entry getEntry(ThreadLocal key) {
//通过散列获取Entry的储存位置i
int i = key.threadLocalHashCode & (table.length - 1);
Entry e = table[i];
if (e != null && e.get() == key)
return e;
else
//如果直接散列无法获取则遍历整个Map直到找到
return getEntryAfterMiss(key, i, e);
}
private void set(ThreadLocal key, Object value) {
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();
}
private void remove(ThreadLocal key) {
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)]) {
if (e.get() == key) {
e.clear();
expungeStaleEntry(i);
return;
}
}
}```
所以get()方法获取当前的Thread对象,再通过Thread对象获得ThreadLocalMap对象,然后获取Entry的value,因为ThreadLocal对象是可以传范型的,所以对于Looper来说,得到的是Looper对象。
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();```
所以myLooper()方法得到的是当前线程的Looper对象。
如果得到的ThreadLocalMap为空,则调用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;
}
protected T initialValue() {
return null;
}
initialValue()方法初始返回的是空,如果我们没有重写这个方法,在没有调用set(T value)方法时,我们调用get()方法返回的是null,如果重写了,返回的值就是我们重写的返回值。
说完get(),我们来说说set():
public void set(T value) {
//通过当前线程获取ThreadLocalMap
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
//如果map对象是空,则新建并赋值给Thread的threadLocals,如果不为空则重设
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}```
set()方法的代码,一目了然。就是给ThreadLocalMap的value设值。
同时ThreadLocal也有一个remove操作:
``` java
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
//获取当前ThreadLocal为key对应的value并移除。
private void remove(ThreadLocal key) {
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)]) {
if (e.get() == key) {
e.clear();
expungeStaleEntry(i);
return;
}
}
}```