來(lái)源:飛天小牛肉
每個(gè)線程都有自己的一個(gè) ThreadLocalMap,ThreadLocal 持有的數(shù)據(jù)就是存在這個(gè) Map 里的(Thread.ThreadLocalMap threadLocals),所以能夠?qū)崿F(xiàn)線程隔離,畢竟每個(gè)線程的 ThreadLocalMap 都是不一樣的
那如果子線程想要拿到父線程的中的 ThreadLocal 值怎么辦呢 ?
比如會(huì)有以下的這種代碼的實(shí)現(xiàn)。在子線程中調(diào)用 get 時(shí),我們拿到的 Thread 對(duì)象是當(dāng)前子線程對(duì)象,對(duì)吧,每個(gè)線程都有自己獨(dú)立的 ThreadLocal,那么當(dāng)前子線程的 ThreadLocalMap 是 null 的(而父線程,也就是 main 線程中的 ThreadLocalMap 是有數(shù)據(jù)的),所以我們得到的 value 也是 null
publicclassThreadLocalTest{
privatestaticThreadLocalthreadLocal=newThreadLocal();
publicstaticvoidmain(String[]args)throwsException{
threadLocal.set("芋道源碼");
System.out.println("父線程的值:"+threadLocal.get());
newThread(newRunnable(){
@Override
publicvoidrun(){
System.out.println("子線程的值:"+threadLocal.get());
}
}).start();
Thread.sleep(2000);
}
}
結(jié)果輸出如下:
父線程的值:芋道源碼
子線程的值:null
要如何解決這個(gè)問(wèn)題呢?
我們先來(lái)從 Thread 類中找找思路:
你會(huì)發(fā)現(xiàn),在 ThreadLocalMap threadLocals 的下方,還有一個(gè) ThreadLocalMap 變量 inherittableThreadLocals
,inherit 翻譯為繼承
先看下這個(gè)變量的注釋:InheritableThreadLocal values pertaining to this thread. This map is maintained by the InheritableThreadLocal
class.
oho,這里出現(xiàn)了一個(gè)渣渣輝都從未體驗(yàn)過(guò)的傳新類:InheritableThreadLocal
翻譯一下注釋,大概就是,如果你使用 InheritableThreadLocal
,那么保存的數(shù)據(jù)都已經(jīng)不在原來(lái)的 ThreadLocal.ThreadLocalMap threadLocals
里面了,而是在一個(gè)新的 ThreadLocal.ThreadLocalMap inheritableThreadLocals
變量中了。
所以,如果想讓上面那段代碼中,子線程能夠拿到父線程的 ThreadLocal 值,只需要把 ThreadLocal 聲明改為 InheritableThreadLocal 就可以了
下面我們具體來(lái)看下 InheritableThreadLocal
是怎么做到父子線程傳值的。
首先看下 new Thread 的時(shí)候線程都做了些什么 Thread#init()
privatevoidinit(ThreadGroupg,Runnabletarget,Stringname,longstackSize,AccessControlContextacc){
//省略部分代碼
Threadparent=currentThread();
if(inheritThreadLocals&&parent.inheritableThreadLocals!=null)
//copy父線程的map,創(chuàng)建一個(gè)新的map賦值給當(dāng)前線程的inheritableThreadLocals
this.inheritableThreadLocals=
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
//省略部分代碼
}
核心其實(shí)就是上面幾句代碼,如果你設(shè)置了 inheritableThreadLocals 變量,那么 Thread 就會(huì)把父線程 ThreadLocal threadLocals
中的所有數(shù)據(jù)都 copy 到子線程的 InheritableThreadLocal inheritableThreadLocals
中 。
而且,copy 調(diào)用的 createInheritedMap 方法其實(shí)是一個(gè)淺拷貝函數(shù),key 和 value 都是原來(lái)的引用地址,這里所謂的 copy 其實(shí)就是把一個(gè) Map 中的數(shù)據(jù)復(fù)制到另一個(gè) Map 中:
至此,大致的解釋了 InheritableThreadLocal
為什么能解決父子線程傳遞 Threadlcoal 值的問(wèn)題了,總結(jié)下:
-
在創(chuàng)建
InheritableThreadLocal
對(duì)象的時(shí)候賦值給線程的 t.inheritableThreadLocals 變量 - 在創(chuàng)建新線程的時(shí)候會(huì) check 父線程中 t.inheritableThreadLocals 變量是否為 null,如果不為 null 則 copy 一份數(shù)據(jù)到子線程的 t.inheritableThreadLocals 成員變量中去
-
InheritableThreadLocal
重寫了 getMap(Thread) 方法,所以 get 的時(shí)候,就會(huì)從 t.inheritableThreadLocals 中拿到 ThreadLocalMap 對(duì)象,從而實(shí)現(xiàn)了可以拿到父線程 ThreadLocal 中的值
審核編輯 :李倩
-
數(shù)據(jù)
+關(guān)注
關(guān)注
8文章
7077瀏覽量
89161 -
變量
+關(guān)注
關(guān)注
0文章
613瀏覽量
28404 -
線程
+關(guān)注
關(guān)注
0文章
505瀏覽量
19705
原文標(biāo)題:ThreadLocal 父子線程之間該如何傳遞數(shù)據(jù)?
文章出處:【微信號(hào):芋道源碼,微信公眾號(hào):芋道源碼】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論