天天看點

java ThreadLocal 原理說明

準備工作

建立一個共享變量ThreadLocal

再建立一個向共享變量ThreadLocal 中指派的線程

再建立一個從共享變量ThreadLocal 中取值的線程

如下圖所示:tl為共享變量ThreadLocal

TestThreadForSet 為指派線程;TestThreadForGet 為取值線程,

為保證指派線程先于取值線程執行,中間加入了等待2秒

java ThreadLocal 原理說明
java ThreadLocal 原理說明
java ThreadLocal 原理說明

運作結果:

如果ThreadLocal 為普通的共享變量,那麼取到的值一定為指派線程中設定的值。

然而:實際運作結果如下:

java ThreadLocal 原理說明

下面來說明為什麼會這樣:

首先我們需要了解指派線程指派的時候,把值存儲到哪裡去了?

我們跟蹤下ThreadLocal的set方法

java ThreadLocal 原理說明

1:首先擷取目前線程,然後執行了getMap方法,參數為目前線程,我們下面看getMap方法

java ThreadLocal 原理說明

這裡是重點,直接傳回的是線程内部的執行個體變量threadLocals,注意這裡是線程内部的執行個體變量,也就是說實際運作過程中每個線程都有一個threadLocals變量,這個變量的類型ThreadLocalMap。如下圖

java ThreadLocal 原理說明

2:getMap執行完後,我們再傳回到set方法中,這個時候會判斷map是否為空,因為我們是第一次指派,是以map肯定為null

,然後執行createMap方法,方法參數為目前線程對象,以及你要指派的變量。

java ThreadLocal 原理說明

3:我們看到這裡給線程的threadLocals變量指派了一個新的對象,這裡再次聲明一下,threadLocals是目前線程的執行個體變量,每個線程不共享,即如果有10個線程那麼就會有10個threadLocals變量,每個線程一個。下面我們看new ThreadLocalMap(this, firstValue);做了什麼,這個構造方法中第一個參數為this,這個this指向的是threadLocal變量,也就是在main方法中聲明的變量tl,看下圖

java ThreadLocal 原理說明

注意跟上面的threadLocals區分開;這個構造方法中第二個參數為你指派的内容。

java ThreadLocal 原理說明

4:上圖中構造方法裡的内容,這裡總結成一句話就是 以Threadlocal(這裡沒有s)變量對象為key,以你指派的内容為value放到ThreadLocalMap中。

總結一下,下圖中這幾條語句的主要邏輯是,首先擷取目前線程中的一個執行個體變量map,如果擷取到的map為空,那麼就建立一個map,并把ThreadLocal變量作為key,自定義指派内容為value放到map中,如果不為空,那就直接放了,相信很多同學都寫過這樣的邏輯。

java ThreadLocal 原理說明

到此為止,我們講了set方法的邏輯。下面我們看下get方法的邏輯,get方法的邏輯其實就是到目前線程的threadLocals變量(ThreadLocalMap類型)裡找this為key對應的value,this變量指的是ThreadLocal共享變量tl。注意這裡又提到了目前線程。

java ThreadLocal 原理說明

我們用一張圖總結一下上面的内容

java ThreadLocal 原理說明