ThreadLocal的主要实现如下:
ThreadLocal中有一个静态内部类,名为ThreadLocalMap,主要定义如下:
* ThreadLocalMap is a customized hash map suitable only for
* maintaining thread local values. No operations are exported
* outside of the ThreadLocal class. The class is package private to
* allow declaration of fields in class Thread. To help deal with
* very large and long-lived usages, the hash table entries use
* WeakReferences for keys. However, since reference queues are not
* used, stale entries are guaranteed to be removed only when
* the table starts running out of space.
*/
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<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
注意看其中的说明:
- ThreadLocalMap是个定制的HashMap,所以很多HashMap的实现,这里其实都有类似的东西。
- ThreadLocalMap的Entrty元素,注意是WeakReference类型,想想weakReference的特点嘞,它跟SoftReference的区别就是:
- SoftReference指向的对象,只有在内存不足时才会被GC回收掉。
- 只有WeakReference指向的对象,在下次GC的时候一般就会回收掉。
所以这个Entry继承WeakReference,应该只是为了当一个线程结束时,其对应的ThreadLocal数据会尽快的被释放掉。
- Entry中的key值是ThreadLocal本身,value则是你需要存储的数据(Object类型),所以对应到HashMap,可以想到其hashcode就是key的hashcode。
- 每个线程独享一个ThreadLocalMap,比如一个Thread的实现,里面定义了4个ThreadLocal,那么在实际代码运行过程中,只会有一个ThreadLocalMap实例,里面包含了至少4个Entry,分别对应上述的几个ThreadLocal对象。而多个Thread之间,ThreadLocalMap是不共用的,每个线程对象自己维护自己的ThreadLocalMap。
- 关于ThreadLocalMap存放在哪儿,其实跟正常的java对象一样,都是存放在堆空间里,通过线程来获取,如下:
class Thread implements Runnable {
/* Make sure registerNatives is the first thing <clinit> does. */
private static native void registerNatives();
static {
registerNatives();
}
private volatile String name;
...
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
...
通过线程对象 t.threadLocals就可以获取到整个ThreadLocalMap,然后再根据key值获取存入的结果。
- 这里之前看的时候,没有仔细去看对应的实现,以为是放在线程在初始化的时候指定的-Xss分配的堆空间内,但是仔细看过代码之后,发现两者并无关联。这里还是理解不够深,-Xss指定的是Stack space,也就是栈空间,其中是不会存放对象的。