Thread 中 ThreadLocal 源码解读
先了解一下ThreadLocal類提供的幾個方法:
public T get() { } public void set(T value) { } public void remove() { } protected T initialValue() { } get()方法是用來獲取ThreadLocal在當前線程中保存的變量副本,set()用來設置當前線程中變量的副本,remove()用來移除當前線程中變量的副本,initialValue()是一個protected方法,一般是用來在使用時進行重寫的,它是一個延遲加載方法,下面會詳細說明。首先我們來看一下ThreadLocal類是如何為每個線程創建一個變量的副本的。
先看下get方法的實現:
第一句是取得當前線程,然后通過getMap(t)方法獲取到一個map,map的類型為ThreadLocalMap。然后接著下面獲取到<key,value>鍵值對,注意這里獲取鍵值對傳進去的是? this,而不是當前線程t。
如果獲取成功,則返回value值。? ?如果map為空,則調用setInitialValue方法返回value。
我們上面的每一句來仔細分析:
首先看一下getMap方法中做了什么:
可能大家沒有想到的是,在getMap中,是調用當期線程t,返回當前線程t中的一個成員變量threadLocals。
那么我們繼續取Thread類中取看一下成員變量threadLocals是什么:
實際上就是一個ThreadLocalMap,這個類型是ThreadLocal類的一個內部類,我們繼續取看ThreadLocalMap的實現:
可以看到ThreadLocalMap的Entry繼承了WeakReference,并且使用ThreadLocal作為鍵值。
然后再繼續看setInitialValue方法的具體實現:
很容易了解,就是如果map不為空,就設置鍵值對,為空,再創建Map,看一下createMap的實現:
至此,可能大部分朋友已經明白了ThreadLocal是如何為每個線程創建變量的副本的:
首先,在每個線程Thread內部有一個ThreadLocal.ThreadLocalMap類型的成員變量threadLocals,這個threadLocals就是用來存儲實際的變量副本的,鍵值為當前ThreadLocal變量,value為變量副本(即T類型的變量)。
初始時,在Thread里面,threadLocals為空,當通過ThreadLocal變量調用get()方法或者set()方法,就會對Thread類中的threadLocals進行初始化,并且以當前ThreadLocal變量為鍵值,以ThreadLocal要保存的副本變量為value,存到threadLocals。
測試輸出的日志:
調用get方法時,當前線程共享變量沒有設置,調用initialValue獲取默認值! 線程IntegerTask1: 0 調用get方法時,當前線程共享變量沒有設置,調用initialValue獲取默認值! 線程IntegerTask2: 0 調用get方法時,當前線程共享變量沒有設置,調用initialValue獲取默認值! 調用get方法時,當前線程共享變量沒有設置,調用initialValue獲取默認值! 線程StringTask1: a 線程StringTask2: a 線程StringTask1: aa 線程StringTask2: aa 線程IntegerTask1: 1 線程IntegerTask2: 1 線程StringTask1: aaa 線程StringTask2: aaa 線程IntegerTask2: 2 線程IntegerTask1: 2 線程StringTask2: aaaa 線程StringTask1: aaaa 線程IntegerTask2: 3 線程IntegerTask1: 3 線程StringTask1: aaaaa 線程StringTask2: aaaaa 調用get方法時,當前線程共享變量沒有設置,調用initialValue獲取默認值! 線程IntegerTask2: 0 調用get方法時,當前線程共享變量沒有設置,調用initialValue獲取默認值! 線程IntegerTask1: 0從測試輸出的日志可以看出:
ThreadLocalMap 是每一個線程內部自帶的容器,用來存儲共享對象的,其map的key是Threadlocal對象。ThreadLocal new出來一個對象的時候,同時又調用set 設置共享對象的時候,那么ThreadlocalMap 會在set 方法中創建和初始化。然后將當前的threadLocal 作為key,threadLocal 中要set的共享對象作為value存儲到ThreadlocalMap 中。
可見ThreadlocalMap 存儲的共享對象只是在set的時候保證數據對象是一致的,因為threadLocal 設置的共享是同一個對象。
threadLocal 說白了就是對象的共享,想想我們有很對的實現方式,比如static,比如單例的gets,sets。
最常見的ThreadLocal使用場景為 用來解決 數據庫連接、Session管理等。
總結
以上是生活随笔為你收集整理的Thread 中 ThreadLocal 源码解读的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 时珍病之是什么意思
- 下一篇: Thread Join 讲解