1. 程式人生 > >對ThreadLocal實現原理的一點思考

對ThreadLocal實現原理的一點思考

前言


《透徹理解Spring事務設計思想之手寫實現》中,已經向大家揭示了Spring就是利用ThreadLocal來實現一個執行緒中的Connection是同一個,從而保證了事務。本篇部落格將帶大家來深入分析ThreadLocal的實現原理。

 

ThreadLocal是什麼、有什麼、能做什麼?

ThreadLocal提供一個執行緒(Thread)區域性變數,訪問到某個變數的每一個執行緒都擁有自己的區域性變數。說白了,ThreadLocal就是想在多執行緒環境下去保證成員變數的安全。

ThreadLocal提供的方法

ThreadLocal API

對於ThreadLocal而言,常用的方法,就是get/set/initialValue方法。

我們先來看一個例子

demo

執行結果

是你想象中的結果麼?

 

很顯然,在這裡,並沒有通過ThreadLocal達到執行緒隔離的機制,可是ThreadLocal不是保證執行緒安全的麼?這是什麼鬼?

雖然,ThreadLocal讓訪問某個變數的執行緒都擁有自己的區域性變數,但是如果這個區域性變數都指向同一個物件呢?這個時候ThreadLocal就失效了。仔細觀察下圖中的程式碼,你會發現,threadLocal在初始化時返回的都是同一個物件a!

 

看一看ThreadLocal原始碼

我們直接看最常用的set操作:

set

 

執行緒區域性變數

 

createMap

你會看到,set需要首先獲得當前執行緒物件Thread;

然後取出當前執行緒物件的成員變數ThreadLocalMap;

如果ThreadLocalMap存在,那麼進行KEY/VALUE設定,KEY就是ThreadLocal;

如果ThreadLocalMap沒有,那麼建立一個;

說白了,當前執行緒中存在一個Map變數,KEY是ThreadLocal,VALUE是你設定的值。

看一下get操作:

get

這裡其實揭示了ThreadLocalMap裡面的資料儲存結構,從上面的程式碼來看,ThreadLocalMap中存放的就是Entry,Entry的KEY就是ThreadLocal,VALUE就是值。

ThreadLocalMap.Entry:

弱引用?

在JAVA裡面,存在強引用、弱引用、軟引用、虛引用。這裡主要談一下強引用和弱引用。

強引用,就不必說了,類似於:

A a = new A();

B b = new B();

考慮這樣的情況:

C c = new C(b);

b = null;

考慮下GC的情況。要知道b被置為null,那麼是否意味著一段時間後GC工作可以回收b所分配的記憶體空間呢?答案是否定的,因為即便b被置為null,但是c仍然持有對b的引用,而且還是強引用,所以GC不會回收b原先所分配的空間!既不能回收利用,又不能使用,這就造成了記憶體洩露

那麼如何處理呢?

可以c = null;也可以使用弱引用!(WeakReference w = new WeakReference(b);)

分析到這裡,我們可以得到:

記憶體結構圖

這裡我們思考一個問題:ThreadLocal使用到了弱引用,是否意味著不會存在記憶體洩露呢?

首先來說,如果把ThreadLocal置為null,那麼意味著Heap中的ThreadLocal例項不再有強引用指向,只有弱引用存在,因此GC是可以回收這部分空間的,也就是key是可以回收的。但是value卻存在一條從Current Thread過來的強引用鏈。因此只有當Current Thread銷燬時,value才能得到釋放。

因此,只要這個執行緒物件被gc回收,就不會出現記憶體洩露,但在threadLocal設為null和執行緒結束這段時間內不會被回收的,就發生了我們認為的記憶體洩露。最要命的是執行緒物件不被回收的情況,比如使用執行緒池的時候,執行緒結束是不會銷燬的,再次使用的,就可能出現記憶體洩露。

那麼如何有效的避免呢?

事實上,在ThreadLocalMap中的set/getEntry方法中,會對key為null(也即是ThreadLocal為null)進行判斷,如果為null的話,那麼是會對value置為null的。我們也可以通過呼叫ThreadLocal的remove方法進行釋放!

 

好了,到這裡,ThreadLocal的剖析就完成了,自己對ThreadLocal的認識又深入了些,^_^

 

手寫系列相關爆文


【手寫系列】寫出我的第一個框架:迷你版Spring MVC

【手寫系列】透徹理解Spring事務設計思想之手寫實現

【手寫系列】透徹理解MyBatis設計思想之手寫實現

【手寫系列】純手寫實現一個高可用的RPC

【手寫系列】理解資料庫連線池底層原理之手寫實現

【手寫系列】對HashMap的思考及手寫實現

【手寫系列】純手寫實現JDK動態代理

【手寫系列】寫一個迷你版的Tomcat



作者:張豐哲
連結:https://www.jianshu.com/p/ee8c9dccc953
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯絡作者獲得授權並註明出處。