關於ThreadLocal變數的一個坑

劍握在手發表於2017-03-07

每個執行緒都有一個ThreadLocalMap物件,ThreadLocalMap是Thread的一個內部類,可以把ThreadLocalMap理解成一個Map,這個Map裡存放這一個Thread的所有執行緒變數。

在我們建立一個執行緒變數 maxLife 之後,執行其set方法,其實是以maxLife這個物件為鍵,以0為值,然後將這組鍵值對放入當前執行緒的ThreadLocalMap物件中。

如果你不明白這意味著什麼,接著往下看。

為了說明ThreadLocal有什麼不同,我們直接上程式碼。

 

首先,我們在類中定義一個全域性變數,後邊的所有執行緒都共享這個變數。

ThreadLocal<Integer> maxLife = null;

 

然後建立一個執行緒A,並在這個執行緒中為maxLife賦一個新物件,並且為其設定值

maxLife = new ThreadLocal<Integer>()
maxLife.set(0);

 

這個時候讓A執行緒別再往下跑了,同時我們建立一個B執行緒,然後在B執行緒裡

maxLife = new ThreadLocal<Integer>();

 

執行完這一段,把B暫停了,然後再回到A執行緒,執行

Integer i = maxLife.get();

 

這個時候你如果列印i,那麼你會看到一個null。

 

這是為什麼呢?

因為maxLife的get方法,其實是以maxLife這個物件本身為鍵,然後去當前執行緒的ThreadLocalMap中獲取其所對應的值,A執行緒中我們new了一個物件然後當成key,B執行緒中我們又new了一個,我們知道A和B先後new 的兩個物件不是同一個物件,那麼以不同的物件作為key去一個map裡面取值會怎樣呢?

 

也就是說 maxLife 這個變數,在A和B中是共享的,但是maxLife作為key在A和B各自的ThreadLocalMap中對應的值是不一樣的,所以我們定義ThreadLocal變數,最好在一開始的時候就為其new一個值,而不是讓它等於null。

 

 

完畢。

 

相關文章