开门见山,直接先看ThreadLocal的类结构。
ThreadLocal中定义了两个内部类,SuppliedThreadLocal不在讨论范围,还有一个就是ThreadLocal类了。能使用的方法有withInitial(Supplier<? extends S> supplier)、get()、set(T value)和remove()。
接下来就通过set(T value)方法来解释ThreadLocal、ThreadLocalMap和Thread之间的关系。
set(T value)
/**
* Sets the current thread's copy of this thread-local variable
* to the specified value. Most subclasses will have no need to
* override this method, relying solely on the {@link #initialValue}
* method to set the values of thread-locals.
*
* @param value the value to be stored in the current thread's copy of
* this thread-local.
*/
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
首先是通过Thread的currentThread()获得了当前调用set(T value)方法的线程实例。
/**
* Returns a reference to the currently executing thread object.
*
* @return the currently executing thread.
*/
public static native Thread currentThread();
接下来又调用了自己的getMap(Thread t)方法获得了ThreadLocalMap实例,这里很重要。
/**
* Get the map associated with a ThreadLocal. Overridden in
* InheritableThreadLocal.
*
* @param t the current thread
* @return the map
*/
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
也就是说ThreadLocalMap实例是由每个Thread实例持有的。
在拿到了Map后就是判空,先假设为空,也就是说当前Thread里的ThreadLocalMap实例为空。就会调用createMap(Thread t, T firstValue)方法。
/**
* Create the map associated with a ThreadLocal. Overridden in
* InheritableThreadLocal.
*
* @param t the current thread
* @param firstValue value for the initial entry of the map
*/
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
这里也很重要,可以看出ThreadLocal为Thread的threadLocals成员变量赋予了一个新的ThreadLocalMap实例。
在实例化ThreadLocalMap时还往构造函数中传入了ThreadLocal自身的引用(this)和值(value)。
接下来再看看createMap(Thread t, T firstValue)方法中用到的ThreadLocalMap的构造函数。
/**
* Construct a new map initially containing (firstKey, firstValue).
* ThreadLocalMaps are constructed lazily, so we only create
* one when we have at least one entry to put in it.
*/
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);
}
这里主要就是ThreadLocalMap自己的初始化,不难看出在Map中存放的key是ThreadLocal类型并不是Thread类型。
总结
ThreadLocal自身不持有ThreadLocalMap实例,真正持有ThreadLocalMap实例的是Thread。
ThreadLocal对ThreadLocalMap的操作是通过当前线程Thread实例获得ThreadLocalMap实例,然后再把自身当成key对map进行操作。
- 也就是说如果有多个ThreadLocal类去操作同一个线程,那么线程中的ThreadLocalMap就会有多个键值对。
- 而一个ThreadLocal类在一个线程中只能操作一个key-value。key就是自身,而value的类型可以是自己定义的对象实例。
废话
这里说的比较简单,单纯按照自己的理解写的。还有很多的方法都没有去解释,但是举一反三还是很好理解的。有说的不对的地方还请多多指教。