ThreadLocal原始碼解析及避坑指南

2021-10-08 07:37:28 字數 2742 閱讀 1582

threadlocal 是執行緒私有領地,其他執行緒無法訪問。

本文首先給出乙個簡單的使用示例,接下來主要解析threadlocal的原理,繼而作圖以生動地表示threadlocal的底層儲存關係,探索可能出現的記憶體洩漏,最後給出乙個threadlocal的正確使用姿勢。

你知道嗎?據說這段**可能會造成記憶體洩漏,,,什麼,不知道?

無妨,寫這篇文章之前偶也不知道,一起來學習下吧。

public

static

void

main

(string[

] args)

,"t1").

start()

; system.out.

println

("main thread print tl: "

+ tl.

get())

;}

明確乙個問題

我們知道threadlocal用於儲存執行緒私有變數,那麼變數存在**呢?

答:

threadlocal.threadlocalmap threadlocals = null;
public

void

set(t value)

public t get()

}return

setinitialvalue()

;}

以上,set、get方法原始碼解析完畢,只有寥寥數行**,相當簡單。若還是似懂非懂,無妨,看我作圖:

該圖描述了threadlocal變數的儲存關係。分析一下這個圖:

為什麼r2是弱引用?

答:弱引用特性:只有弱引用指向的物件,每次gc都會被**。這樣子,當r1斷開後,因為唯一指向threadlocal物件的引用r2是弱引用,在下次gc時threadlocal物件就會被**,從而不會造成記憶體洩漏。

tips:因此每次使用完threadlocal,要記得顯示指定 tl = null;

還存在記憶體洩漏嗎?

答:存在。

若threadlocal物件被**,那麼key就會變為null,那麼我們再也無法通過原來的key值獲得其對應的value。

因為r3是強引用,所以threadlocalmap會一直存在,進而value被threadlocalmap通過r4(強引用)所引用,也會一直存在。

value一直存在於記憶體,而再也不會被訪問到,這也是記憶體洩漏。

tips:每次用完threadlocal,顯示地刪除這個變數。tl.remove();

經過以上學習,下面給出乙個筆者認為完善的示例,防止記憶體洩漏。

public

static

void

main

(string[

] args)

框架中的應用。spring採用threadlocal的方式,來保證單個執行緒中的資料庫操作使用的是同乙個資料庫連線。

實際工作中的應用。我們知道******dataformat不是執行緒安全的。所以如果宣告為全域性變數會有併發安全隱患。一般會在使用這個類的方法裡建立******dataformat物件,這樣不會有併發隱患。但是方法內部的物件在方法執行完其生命週期就結束了,如果乙個請求在呼叫鏈路的n個方法中都呼叫了******dataformat,是不是要建立n個物件?此時我們可以將其宣告為threadlocal,乙個執行緒在其生命週期內使用同乙個******dataformat,不同物件之間使用各自的******dataformat物件,形成執行緒間的資料隔離,不會有併發安全隱患。然而這種場景,適用於乙個執行緒有多個方法呼叫都用到了******dataformat,可以減少建立物件的次數。如果生命週期內只有乙個方法使用了這個物件,在方法裡建立就好了。

thread中還存在乙個屬性inheritablethreadlocals,可以繼承父執行緒中的inheritablethreadlocals 的值。

/*

* inheritablethreadlocal values pertaining to this thread. this map is

* maintained by the inheritablethreadlocal class.

*/threadlocal.threadlocalmap inheritablethreadlocals = null;

建立執行緒物件的時候,有如下一行**。若inheritthreadlocals 是true,且父執行緒的inheritablethreadlocals 不是null,則當前執行緒的inheritablethreadlocals 使用父執行緒中inheritablethreadlocals 的值。

if

(inheritthreadlocals && parent.inheritablethreadlocals != null)

this

.inheritablethreadlocals =

threadlocal.

createinheritedmap

(parent.inheritablethreadlocals)

;

ThreadLocal原始碼理解

threadlocal其實原理是建立了多份相同資料儲存在堆記憶體上,每個執行緒的thread類裡有threadlocal.threadlocalmap threadlocals的屬性來指向存位置,所以每個執行緒修改都不會影響到其他執行緒的資料 首先說下下面用到的東西 threadlocalmap為t...

ThreadLocal原始碼分析

在理解handler looper之前,先來說說threadlocal這個類,聽名字好像是乙個本地執行緒的意思,實際上它並不是乙個thread,而是提供乙個與執行緒有關的區域性變數功能,每個執行緒之間的資料互不影響。我們知道使用handler的時候,每個執行緒都需要有乙個looper物件,那麼and...

ThreadLocal 原始碼解讀

在正式讀 前先簡單介紹threadlocal的實現方式。每個執行緒都會有乙個threadlocalmap,只有在使用到threadlocal的時候才會初始化threadlocalmap。需要儲存的物件t會被放到entry裡面儲存在threadlocalmap的陣列中,entry是乙個鍵值對的資料結構...