深入淺出解析Java ThreadLocal原理_第1頁
深入淺出解析Java ThreadLocal原理_第2頁
深入淺出解析Java ThreadLocal原理_第3頁
深入淺出解析Java ThreadLocal原理_第4頁
深入淺出解析Java ThreadLocal原理_第5頁
已閱讀5頁,還剩2頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

第深入淺出解析JavaThreadLocal原理staticThreadLocalStringlocalStr=newThreadLocal();

staticInheritableThreadLocalStringinheritableLocalStr=newInheritableThreadLocal();

publicstaticvoidmain(String[]args)throwsInterruptedException{

inheritableLocalStr.set("main線程第一次為inheritableLocalStr設(shè)置的值");

newThread(newRunnable(){

@Override

publicvoidrun(){

log.debug("子線程第一次訪問inheritableLocalStr:"+inheritableLocalStr.get());

try{

Thread.sleep(1000);

}catch(InterruptedExceptione){

e.printStackTrace();

log.debug("子線程第二次訪問inheritableLocalStr:"+inheritableLocalStr.get());

}).start();

Thread.sleep(500);

inheritableLocalStr.set("main線程第二次為inheritableLocalStr設(shè)置的值");

log.debug("main線程第二次為inheritableLocalStr賦值");

Thread.sleep(1000);

看下輸出:

可以發(fā)現(xiàn),子線程創(chuàng)建出來后,對(duì)父線程中inheritThreadLocals的修改操作,對(duì)子線程不可見。

總結(jié)

ThreadLocal不可繼承,threadLocals是當(dāng)前線程的成員變量,在子線程中不可見。

InheritableThreadLocal可繼承,原理是:在新建子線程的時(shí)候,將父線程中inheritThreadLocals所有的entry拷貝給了子線程。

子線程創(chuàng)建出來后,對(duì)父線程中inheritThreadLocals的修改操作,對(duì)子線程不可見。

4.存在的內(nèi)存泄露問題

要充分理解ThreadLocal中存在的內(nèi)存泄露問題,需要有以下JVM對(duì)內(nèi)存管理的前置知識(shí)(這里篇幅問題就不補(bǔ)充了):

什么是內(nèi)存泄露?

什么是強(qiáng)引用?

什么是弱引用?

何時(shí)GC?

強(qiáng)引用和弱引用GC時(shí)的區(qū)別?

在分析上述ThreadLocalMap源碼的時(shí)候,注意到有一個(gè)小細(xì)節(jié),ThreadLocalMap的Entry繼承了WeakReferenceThreadLocal,也就是說Entry的key是一個(gè)對(duì)ThreadLocal的弱引用。問題來了,為什么這里要使用弱引用呢?

使用強(qiáng)引用會(huì)如何?

現(xiàn)在假設(shè)Entry的key是一個(gè)對(duì)ThreadLocal的強(qiáng)引用,當(dāng)ThreadLocal對(duì)象使用完后,外部的強(qiáng)引用不存在,但是因?yàn)楫?dāng)前線程對(duì)象中的threadLocals還持有ThreadLocal的強(qiáng)引用,而threadLocals的生命周期是和線程一致的,這個(gè)時(shí)候,如果沒有手動(dòng)刪除,整個(gè)Entry就發(fā)生了內(nèi)存泄露。

使用弱引用會(huì)如何?

現(xiàn)在假設(shè)Entry的key是一個(gè)對(duì)ThreadLocal的弱引用,當(dāng)ThreadLocal對(duì)象使用完后,外部的強(qiáng)引用不存在,此時(shí)ThreadLocal對(duì)象只存在Entry中key對(duì)它的弱引用,在下次GC的時(shí)候,這個(gè)ThreadLocal對(duì)象就會(huì)被回收,導(dǎo)致key為null,此時(shí)value的強(qiáng)引用還存在,但是value已經(jīng)不會(huì)被使用了,如果沒有手動(dòng)刪除,那么這個(gè)Entry中的key就會(huì)發(fā)生內(nèi)存泄露。

使用弱引用還有一些好處,那就是,當(dāng)key為null時(shí),ThreadLocalMap中最多存在一個(gè)key為null,并且當(dāng)調(diào)用set(),get(),remove()這些方法的時(shí)候,是會(huì)清除掉key為null的entry的。

set()、get()、remove()方法中相關(guān)實(shí)現(xiàn)

從下可以發(fā)現(xiàn),set方法首先會(huì)進(jìn)入一個(gè)循環(huán)。

在這個(gè)循環(huán)中,會(huì)遍歷整個(gè)Entry數(shù)組。直到遇到一個(gè)空的entry,退出循環(huán)。

當(dāng)遇到已存在的key'時(shí),會(huì)直接替換value,然后返回。

當(dāng)遇到key為空的entry的時(shí)候,會(huì)直接將當(dāng)前的entry存在這個(gè)過時(shí)的entry中,然后返回。

通過這個(gè)方法的源碼可以看出,key為null的那個(gè)entry實(shí)際上遲早會(huì)被替換成新的entry。

privatevoidset(ThreadLocalkey,Objectvalue){

//Wedon'tuseafastpathaswithget()becauseitisat

//leastascommontouseset()tocreatenewentriesas

//itistoreplaceexistingones,inwhichcase,afast

//pathwouldfailmoreoftenthannot.

Entry[]tab=table;

intlen=tab.length;

inti=key.threadLocalHashCode(len-1);

for(Entrye=tab[i];

e!=null;

e=tab[i=nextIndex(i,len)]){

ThreadLocalk=e.get();

if(k==key){

e.value=value;

return;

//發(fā)現(xiàn)key為空

if(k==null){

replaceStaleEntry(key,value,i);

return;

tab[i]=newEntry(key,value);

intsz=++size;

if(!cleanSomeSlots(i,sz)sz=threshold)

rehash();

privatestaticintnextIndex(inti,intlen){

return((i+1len)i+1:0);

同理,可以看到在get方法中也存在:

privateEntrygetEntry(ThreadLocalkey){

inti=key.threadLocalHashCode(table.length-1);

Entrye=table[i];

if(e!=nulle.get()==key)

returne;

else

returngetEntryAfterMiss(key,i,e);

privateEntrygetEntryAfterMiss(ThreadLocalkey,inti,Entrye){

Entry[]tab=table;

intlen=tab.length;

while(e!=null){

ThreadLocalk=e.get();

if(k==key)

returne;

//替換過時(shí)的entry

if(k==null)

expungeStaleEntry(i);

else

i=nextIndex(i,len);

e=tab[i];

returnnull;

remove()方法中也是一樣:

privatevoidremove(ThreadLocalkey){

Entry[]tab=table;

intlen=tab.length;

inti=key.threadLocalHashCode(len-1);

for(Entrye=tab[i];

e!=null;

e=tab[i=nextIndex(i,len)]){

//清除過時(shí)的key

if(e.get()==key){

e.clear();

expungeStaleEntry(i);

return;

ThreadLocal如果對(duì)ThreadLocalMap的key使用強(qiáng)引用,那么會(huì)存在整個(gè)entry發(fā)生內(nèi)存泄露的問題,如果不手動(dòng)清除,那么這個(gè)不被使用的entry會(huì)一直存在。

ThreadLocal如果對(duì)ThreadLocalMap的key使用弱引用,那么可能會(huì)存在一個(gè)entry的value發(fā)生內(nèi)存泄露,但是在調(diào)用set(),get(),remove()方法時(shí),key為null的entry會(huì)被清除掉。

發(fā)生內(nèi)存泄露最根本的原因是:threadLocals的生命周期是和線程一致的。

每次使用完ThreadLocal對(duì)象后,必須調(diào)用它的remove()方法清除數(shù)據(jù)。

5.ThreadLocal應(yīng)用

ThreadLocal把數(shù)據(jù)存放到線程本地,解決了線程安全問題,沒有使用鎖,直接訪問線程本地變量,效率較高(空間換時(shí)間。)

同時(shí)thr

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論