ThreadLocal的主要實(shí)現(xiàn)如下:
ThreadLocal中有一個(gè)靜態(tài)內(nèi)部類挎挖,名為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;
}
}
注意看其中的說(shuō)明:
- ThreadLocalMap是個(gè)定制的HashMap荞雏,所以很多HashMap的實(shí)現(xiàn)段标,這里其實(shí)都有類似的東西白粉。
- ThreadLocalMap的Entrty元素昔穴,注意是WeakReference類型暖侨,想想weakReference的特點(diǎn)嘞冬念,它跟SoftReference的區(qū)別就是:
- SoftReference指向的對(duì)象趁窃,只有在內(nèi)存不足時(shí)才會(huì)被GC回收掉。
- 只有WeakReference指向的對(duì)象急前,在下次GC的時(shí)候一般就會(huì)回收掉醒陆。
所以這個(gè)Entry繼承WeakReference,應(yīng)該只是為了當(dāng)一個(gè)線程結(jié)束時(shí)裆针,其對(duì)應(yīng)的ThreadLocal數(shù)據(jù)會(huì)盡快的被釋放掉刨摩。
- Entry中的key值是ThreadLocal本身,value則是你需要存儲(chǔ)的數(shù)據(jù)(Object類型)世吨,所以對(duì)應(yīng)到HashMap澡刹,可以想到其hashcode就是key的hashcode。
- 每個(gè)線程獨(dú)享一個(gè)ThreadLocalMap耘婚,比如一個(gè)Thread的實(shí)現(xiàn)罢浇,里面定義了4個(gè)ThreadLocal,那么在實(shí)際代碼運(yùn)行過(guò)程中边篮,只會(huì)有一個(gè)ThreadLocalMap實(shí)例己莺,里面包含了至少4個(gè)Entry奏甫,分別對(duì)應(yīng)上述的幾個(gè)ThreadLocal對(duì)象。而多個(gè)Thread之間凌受,ThreadLocalMap是不共用的阵子,每個(gè)線程對(duì)象自己維護(hù)自己的ThreadLocalMap。
- 關(guān)于ThreadLocalMap存放在哪兒胜蛉,其實(shí)跟正常的java對(duì)象一樣挠进,都是存放在堆空間里,通過(guò)線程來(lái)獲取誊册,如下:
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;
...
通過(guò)線程對(duì)象 t.threadLocals就可以獲取到整個(gè)ThreadLocalMap领突,然后再根據(jù)key值獲取存入的結(jié)果。
- 這里之前看的時(shí)候案怯,沒(méi)有仔細(xì)去看對(duì)應(yīng)的實(shí)現(xiàn)君旦,以為是放在線程在初始化的時(shí)候指定的-Xss分配的堆空間內(nèi),但是仔細(xì)看過(guò)代碼之后嘲碱,發(fā)現(xiàn)兩者并無(wú)關(guān)聯(lián)金砍。這里還是理解不夠深,-Xss指定的是Stack space麦锯,也就是椝〕恚空間,其中是不會(huì)存放對(duì)象的扶欣。