丨線程本地存儲模式沒有共享就傷害_第1頁
丨線程本地存儲模式沒有共享就傷害_第2頁
丨線程本地存儲模式沒有共享就傷害_第3頁
丨線程本地存儲模式沒有共享就傷害_第4頁
丨線程本地存儲模式沒有共享就傷害_第5頁
已閱讀5頁,還剩15頁未讀, 繼續(xù)免費閱讀

付費下載

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

我們在《11|Java線程(下):為什么局部變量是線程安全的?》中提到過線程封閉,其以做到呢?有的,Java語言提供的線程本地(ThreadLocal)就能夠做到。下面我們先看看ThreadLocal到底該如何使用。下面這個靜態(tài)類ThreadId會為每個線程分配一個唯一的線程Id,如果一個線程前后兩次調用ThreadId的get()方法,兩次get()方法的返回值是相同的。但如果是兩個線程分別調用ThreadId的get()方法,那么兩個線程看到的get()方法的返回值是不同的。若你是初次接觸ThreadLocal,可能會覺得奇怪,為什么相同線程調用get()方法結果就相同,而不同線程調用get()方法結果就不同呢?1staticclassThreadId2staticfinal3nextId=new4//定義ThreadLocal5staticfinal67()-8//此方為每個線程分配一個唯一的9staticlongreturn}}能有這個奇怪的結果,都是ThreadLocal的杰作,不過在詳細解釋ThreadLocal的工作原理之前,我們再看一個實際工作中可能遇到的例子來加深一下對ThreadLocal的理解。你可能知道SimpleDateFormat不是線程安全的,那如果需要在并發(fā)場景下使用它,你該怎ThreadLocalThreadLocal的具體實現,這段代碼與前面ThreadId的代碼高度相似,同樣地,不同線程調用SafeDateFormat的get()方法將返回不同的SimpleDateFormat對象實例,由于不同線程并不共享SimpleDateFormat,所以就像局部變量一樣,是線程安全的。staticclassSafeDateFormat//定義ThreadLocalstaticfinal()->new"yyyy-MM-dd7staticDateFormatreturn 11////返回的dfDateFormatdfThreadLocal詳細解釋ThreadLocal的工作原理。在解釋ThreadLocal的工作原理之前,你先自己想想:如果讓你來實現ThreadLocal的功能,你會怎么設計呢?ThreadLocal的目標是讓不同的線程有不同的變量V,那最直接的方法就是創(chuàng)建一個Map,它的Key是線程,Value是每個線程擁有的變量V,ThreadLocal內部持有這樣的一個Map就可以了。你可以參考下面的示意圖和示例代碼來ThreadLocal持有Map1classMyThreadLocal<T>2Map<Thread,T>locals3new4//5Tget()6return78}9//voidset(Tt)Thread.currentThread(),}}那Java的ThreadLocal是這么實現的嗎?這一次我們的設計思路和Java的實現差異很大。Java的實現里面也有一個Map,叫做ThreadLocalMap,不過持有ThreadLocalMapThreadLocalThread。Thread性threadLocals,其類型就是ThreadLocalMap,ThreadLocalMap的Key是ThreadLocal。你可以結合下面的示意圖和精簡之后的Java實現代碼來理解。Thread持有ThreadLocalMapclassThread//內部持有5classpublicTget()//ThreadLocalMapmap//在ThreadLocalMap//Entryereturn staticclass//內部是數組而不是Entry[]//根據ThreadLocal查找EntrygetEntry(ThreadLocal// //EntrystaticclassEntryObject 32初看上去,我們的設計方案和Jaa的實現僅僅是Map的持有方不同而已,我們的設計里面Map屬于ThreaLoal,而Jaa的實現里面ThreaLocalMap則是屬于Thread兩種方式哪種更合理呢?很顯然Jaa的實現更合理一些。在Java的實現方案里面,ThreaLocal僅僅是一個工具類,內部并不持有任何與線程相關的數據,所有和線程相關的數據都在Thread里面,這樣的設計容易理解。而從數據的親緣性上來講,ThreaLocalMap屬于Thread也更加合理。ThreadLocal持有的Map會持有Thread對象的,這就意味著,只要ThreadLocal對象存在,那么Map中的Thread對象就不會被回收。ThreadLocal的生命周期往往都比線程要長,所以這種設計方案很容易導致內存。而Java的實現中Thread持有ThreadLocalMap,而且ThreadLocalMap里對ThreadLocal的還是弱(WeakReference),ThreadThreadLocalMap回收。Java的這種實現方案雖然看上去復雜一些,但是更加安全。Java的ThreaLocal實現應該稱得上深思熟慮了,不過即便如此深思熟慮,還是不能百分百地讓程序員避免內存,例如程池中使用ThreaLocal,如果不謹慎就可能導致內存。程池中使用ThreadLocal為什么可能導致內存呢?原因就出程池中線程的存活時間太長,往往都是和程序同生共死的,這就意味著Thread持有的ThreadLocalMap一直都不會被回收,再加上ThreadLocalMap中的Entry對ThreadLocal是弱(WeakReference),ThreadLocal但是Entry中的Value卻是被Entry強的,所以即便Value的生命周期結束了,Value也是無法被回收的,從而導致內存。那程池中,我們該如何正確使用ThreaLoal呢?其實很簡單,既然JVM不能做到自動釋放對le的強,那我們手動釋放就可以了。如何能做到手動釋放呢?估計你馬上想到try{}fnall{}方案了,這個簡直就是手動釋放資源的利器。示例的代碼如下,你可以參考學習。ExecutorServiceThreadLocal//ThreadLocaltry//}finally//手動清理 12通過ThreadLocal創(chuàng)建的線程變量,其子線程是無法繼承的。也就是說你程中通過ThreadLocal創(chuàng)建了線程變量V,而后該線程創(chuàng)建了子線程,你在子線程中是無法通過ThreadLocal來父線程的線程變量V的。如果你需要子線程繼承父線程的線程變量,那該怎么辦呢?其實很簡單,Java提供了InheritableThreadLocalInheritableThreadLocalThreadLocal類,所以用法和ThreadLocal相同,這里就不多介紹了。不過,我完全不建議你中使用InheritableThreadLocal,不僅僅是因為它具有ThreadLocal相同的缺點——可能導致內存,更重要的原因是:線中線程的創(chuàng)建InheritableThreadLocal,線程本地模式本質上是一種避免共享的方案,由于沒有共享,所以自然也就沒有并發(fā)問題。如果你需要在并發(fā)場景中使用一個線程不安全的工具類,最簡單的方案就是避免共享。避免共享有兩種方案,案是將這個工具類作為局部變量使用,另外案就是線程本地模式。這兩種方案,局部變量方案的缺點是在高并發(fā)場景下會頻繁創(chuàng)建對象,而線程本地方案,每個線程只需要創(chuàng)建一個工具類的實例,所以不存在頻繁創(chuàng)建對象的問題。線程本地模式是解決并發(fā)問題的常用方案,所以JavaSDK也提供了相應的實現:ThreadLocal。通過上面我們的分析,你應該能體會到JavaSDK的實現已經是深思熟慮了,不過即便如此,仍不能,例如中使用ThreadLocal仍可能導致內存泄漏,所以使用ThreadLocal還是需要你打起精神,足夠謹慎。實際工作中,有很多平臺型的技術方案都是采用ThreadLocal來傳遞一些上下文信息,例如Spring使用ThreadLocal來傳遞事務信息。我們曾經,異步編程已經很成熟了,那你覺得在異步場景中,是否可以使用Spring的事務管理器呢?覺得這篇文章對你有幫助的話,也歡迎把它給的朋友。 不得售賣。頁面已增加防盜追蹤,將依法其上一 29|Copy-on-Write模式:不是延時策略的下一 31|GuardedSuspension模式:等待喚醒機制的規(guī)范實右耳聽 9作者回復: 曉

溫馨提示

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

評論

0/150

提交評論