引言:
週五去面試又被面試的一個問題問啞巴了
面試官:知道ThreadLocal的作用是什麼嗎?
我:ThreadLocal可以把創建的變量只能被當前線程訪問
面試官:那ThreadLocal是怎麼保證把創建的變量只能被當前線程訪問呢?
我:。。。(啞巴了)
在這之前我只記住了ThreadLocal可以把創建的變量只能被當前線程訪問這個結論,但是至於ThreadLocal為什麼可以把創建的變量只能被當前線程訪問卻從來沒有去想過。
先說結論: ThreadLocal的實現原理就是用了ThreadLocal裡面的一個靜態ThreadLocalMap
這個是怎麼操作的呢,往下看
ThreadLocalMap是ThreadLocal裡面的一個靜態類
源碼如下所示
ThreadLocalMap是Thread裡面的一個屬性
為什麼這樣說呢,首先我們看到Thread類裡面有一個屬性就叫做ThreadLocalMap
然後我們看一下ThreadLocal裡面的set()方法,看到源碼可以看到噹噹前線程的ThreadLocalMap是null的時候,此時就會走下面的紅色框裡面的代碼
然後就是會走下面的方法,然後new一個ThreadLocalMap賦值給當前線程的threadLocals這個變量,threadLocals這個變量在Thread裡面就是ThreadLocal.ThreadLocalMap類型的
然後當set()的時候,會把當前實例化對象的ThreadLocal作為key值,然後把set()裡面的參數當成value放到這個ThreadLocalMap裡面
在ThreadLocal裡面源碼set(),此時可以看到set()的源碼就是首先獲取當前線程,然後利用當前線程獲取一個ThreadLocalMap的對象,然後如果ThreadLocalMap對象為空,則把當前ThreadLocal當成key,set()裡面的參數當成value放到ThreadLocalMap集合裡面,否則創建這個ThreadLocalMap對象,然後把當前ThreadLocal當成key,set()裡面的參數當成value放到ThreadLocalMap集合裡面
上面的createMap(t,value)源碼如下
看到上面的代碼之後,我們也能知道為什麼ThreadLocal可以把創建的變量只能被當前線程訪問,其他線程則無法訪問和修改,因為ThreadLocal的值是放入了當前線程的一個ThreadLocalMap實例中,所以只能在本線程中訪問,其他線程無法訪問。
Jdk1.8的ThreadLocalMap
看源碼發現在jdk1.8裡面,ThreadLocalMap裡面是用Entry[]這個數組來實現ThreadLocalMap的功能。使用過程是:Entry類裡面的key值就是ThreadLocal,並且是弱引用,然後Entry類裡面的value屬性對應放入到ThreadLocalMap調用set方法裡面的第二個參數
看代碼:下面是 jdk1.8裡面的ThreadLocalMap類裡面的set方法,然後下面的紅色框裡面的使用的就是Entry類
Entry類就是指ThreadLocalMap類裡面的Entry類,如下所示
然後我們看一下ThreadLocalMap裡面的set()方法是怎麼進行存儲的
首先可以看到下面的紅色框裡面的threadLocalHashCode就是獲取當前ThreadLocal實例對象的threadLocalHashCode屬性,這個threadLocalHashCode屬性就是唯一的,它是怎麼來的呢,看下面的圖片,首先是ThreadLocal類裡面的HASH_INCREMENT常量,然後通過下面的nextHashCode()方法來進行原子性的增加1,然後把nextHashCode()方法的返回值給當前的ThreadLocal實例化對象的threadLocalHashCode屬性,這樣就保證唯一性了
然後把這個ThreadLocal的threadLocalHashCode值當成ThreadLocalMap類裡面的Entry數組的索引值,就是下面的綠色框裡面的代碼,這樣就把ThreadLocal調用的set()方法的兩個參數都存儲到ThreadLocalMap裡面的Entry數組裡面了
到此ThreadLocal的源碼探究就結束了,眼前閱讀的讀者您懂了嗎,有什麼不清楚的,歡迎留言,一起探究啊
最後送上福利一張
關鍵字: 源碼 ThreadLocalMap ThreadLocal