准备知识:ThreadLocal
首先要搞清楚ThreadLocal的作用是什么,然后再去看它的源码。ThreadLocal的作用是为了实现线程间的数据隔离。(分析源码就要分析为什么ThreadLocal能做到数据隔离,以及,它在Handler中起了什么作用?)
第一个问题:ThreadLocal是如何做到数据隔离的?
要搞清楚这个问题,首先我们追踪源码,看一下,ThreadLocal是怎么放置和取出数据的。
1.1 从ThreadLocal中取数据:get()
public T get() {
//拿到当前线程 Thread t = Thread.currentThread(); //拿到当前线程中的 ThreadLocalMap ThreadLocalMap map = getMap(t); //通过下面两步,追踪可以看到,map此时为空。 if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) {
@SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); }
点击进入源码发现这个方法首先是获取到当前的线程,然后拿到当前线程中的ThreadLocalMap。我们追踪其中的getMap(t):
ThreadLocalMap getMap(Thread t) {
return t.threadLocals; }
返回的是threadLocals,这是Thread类中的一个全局变量。追踪进去可以看到: Thread.java
ThreadLocal.ThreadLocalMap threadLocals = null; threadLocals = null;
在Thread.java中,对这个全局变量的定义均为null。因此在get()中,map为空,会走到setInitialValue()中。我们继续追踪到setInitialValue()中。看看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; }
首先调用初始化方法initialValue(),得到value,如果用户重写了initialValue(),那么获得到就是用户定义的返回值。再往下走,得到的Map仍然是null,因此会走到createMap(t, value)中。继续追踪下去,看看createMap()是怎么实现的。
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue); }
在这个方法中,定义了threadLocals这个变量。创建了ThreadLocalMap。
1.2 往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); }
仍然是这样:首先获取当前线程,再通过当前线程获取到 ThreadLocalMap,在之前通过对getMap(t)的分析可以知道,此时的map = null,因此set(t)最终也会走 createMap(t, value)。之前对 createMap(t, value)的源码进行分析过, createMap(t, value)会创建一个ThreadLocalMap,并将value放入ThreadLocalMap中。
看到这里,我们发现,ThreadLocal取数据和拿数据,都是通过一个叫做ThreadLocalMap的类,那么这个类到底是个啥呢?阅读源码发现,ThreadLocalMap是ThreadLocal中的一个静态内部类:
static class ThreadLocalMap {
/** * The entries in this hash map extend WeakReference, using * its main ref field as the key (which is always a * ThreadLocal object). Note that null keys (i.e. entry.get() * == null) mean that the key is no longer referenced, so the * entry can be expunged from table. Such entries are referred to * as "stale entries" in the code that follows. */ static class Entry extends WeakReference> {
/** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal> k, Object v) {
super(k); value = v; } } /** * The initial capacity -- MUST be a power of two. */ private static final int INITIAL_CAPACITY = 16; /** * The table, resized as necessary. * table.length MUST always be a power of two. */ private Entry[] table; .......
这个静态内部类中,还有一个静态内部类,这个类叫做Entry,这个类比较简单,它其中维护了两个变量,分别是ThreadLocal类型的Key和Object类型的Value。在每个ThreadLocalMap中都有一个Entry类型的数组Entry[],用来存储数据。
源码阅读到这里,再结合到上面分析的ThreadLocal源码中set()的实现:
if (map != null) map.set(this, value);
这里的Map指的是ThreadLocalMap,追踪到ThreadLocalMap中的set()
/** * Set the value associated with key. * * @param key the thread local object * @param value the value to be set */ 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) {