ThreadLocal源碼分析

ThreadLocal

是什麼?

首先,咱們從名字上來看就是線程本地的意思,能夠想到在ThreadLocal內的都是獨屬於線程自己。實際也是如此,ThreadLocal對象能夠提供線程局部變量,ThreadLocal爲變量在每一個線程中都建立了一個副本,每一個線程能夠訪問本身內部的副本變量。這也意味着多個線程之間互不干擾。算法

怎麼用?

通常而言,看一個對象先從構造方法開始,可是ThreadLocal的構造方法爲空實現。
image.png數組

那咱們稍微思考一下,既然是儲存變量,那麼重點就該是查詢、增長、刪除的方法,分別對應着:get(),set(),remove()方法。spa

get()方法

image.png

  • 首先,獲取當前線程,根據當前線程獲取Map(ThreadLocal重點)
  • 若是不爲空,則繼續查詢,是否有對應的實體,若是存在則放回。
  • 若是map爲空,或者entry爲空時,則調用setInitialValue()方法。

使用邏輯仍是很清晰的,接着看下setInitialValue()方法
image.png線程

initialValue()方法是子類重寫的方法(),當沒有entity的時候,就在這裏初始化賦值。對象

當map爲空時,則將初始化Map,並將其設置爲第一個Entry。若是是Entry爲空,則設置Entry。blog

如下是建立map的方法:
image.png內存

set()方法

image.png

簡單明瞭的邏輯,map不爲空,則直接設置。若是爲空,則建立一個Map。開發

remove() 方法

image.png

看了三個方法 都與ThreadLocalMap有着深厚的聯繫,那麼接下來就看看這個類吧。rem

ThreadLocalMap

爲何不用HashMap,而是新建一個類呢?
  • 1、定製key的類型,爲弱引用的,以遍處理內存泄漏
  • 2、在 寫數據 和 查數據的時候 ThreadLocalMap會有清理過時數據的功能。
  • 3、爲了清理過時數據,解決hash衝突的方法,從拉鍊法,改爲了線性開發定址法。
  • 4、爲了適應hash衝突解決方法的改變,使數據分佈更加均勻,ThreadLocalMap重寫了hash算法。使用魔數疊加的hash,能夠保證hash的分佈均勻。
基礎信息
  • 初始容量:16
  • 擴容閾值:2/3
  • hash算法:魔數疊加
  • Entry類型:弱應用 key,正常引用value
resize方法

當擴容達到閾值以後,會觸發rehash方法,先清除一輪過時數據,若是清理數據後,數據容量爲閾值的3/4,則開啓resize方法。get

image.png

resize方法,新建一個數組,將舊數組的從新rehash以後,一一放入後,最後更新引用。並從新計算閾值
image.png

get方法
  • 先根據hash算法找到合適位置,若是這個位置不是,說明發生hash衝突或者不存在,因此須要向後尋找。

image.png

  • 如今就分爲兩種狀況

    • 碰到正常數據,則搜索下一個
    • 碰到null,則開始探測式清理過時邏輯。(這個算是這個類的重要的一個功能)簡要的介紹一下流程

      • 開始向後迭代。遇到正常數據時,判斷是否處於正確位置,若是是,則不處理,若是不是,則rehash,從新定位(由於以前可能清理出一部分空slot),因此從新rehash後的index理論上會更接近應該處在的index(或者直接處於正確位置)。遇到key=null時,會將當前位置置爲空。一直迭代到slot爲空時,結束。

image.png

set方法(理解不夠透徹)
  • 正常狀況,無衝突且爲null,就直接添加。
  • 不爲null,也分爲兩種狀況,先碰到可key一致的數據,那麼替換返回直接·而後就是鵬達過時數據了,就向後進行查找,若是碰到一個key一致的slot,先更新,而後在於當前的這個slot進行替換,若是一直都沒有碰到相同的key,那麼直接在當前的這個slot生成這個數據。
  • 而後判斷是否要擴容。
相關文章
相關標籤/搜索