寫個demo測試下:
private static void testThreadLocal() {ThreadLocal<Integer> threadLocal = new ThreadLocal<>();new Thread(){@Overridepublic void run() {threadLocal.set(9527);System.out.println("curr thread: " + Thread.currentThread().getName() + ", set 9527");try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("curr thread: " + Thread.currentThread().getName() + ", getValue: " + threadLocal.get());}}.start();new Thread(){@Overridepublic void run() {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}threadLocal.set(250);System.out.println("curr thread: " + Thread.currentThread().getName() + ", set 250");System.out.println("curr thread: " + Thread.currentThread().getName() + ", getValue: " + threadLocal.get());}}.start();}
打印:
可以看出,同一個ThreadLocal對象,在不同的線程中設置值和取值互不干擾。
研究下源碼。
Thread線程對象里面維護了一個ThreadLocalMap對象,上面示例中設置的值都是存在對應線程的ThreadLocalMap對象中,ThreadLocalMap用于存儲其對應線程的數據:
看下如何創建ThreadLocalMap:
可以看出,ThreadLocalMap中有個table數組,用于存儲Entry(鍵:ThreadLocal對象,值為需要保存的對象)。 table數組初始長度只有16, 根據threadLocalHashCode & 15得到索引,該索引范圍0 - 15。?
后續table數組容量不夠了會擴容該數組:
再看下Entry類:
繼承了弱引用,當ThreadLocal對象沒有強引用時可以被GC回收。
ThreadLocal核心方法:
1、set, 將需要保存的值保存到當前線程的ThreadLocalMap對象中。上面分析過,是通過鍵值對的方式保存,key為該ThreadLocal對象,value為要保存的對象。
2、get, 從當前線程的ThreadLocalMap中取出該ThreadLocal存的對象。
3、remove, 當存儲數據不再使用時,記得調用remove方法移除數據,防止內存泄漏:
ok. 總結,通過ThreadLocal存儲數據是存到調用線程中,不同線程存儲的數據是互相獨立的。可用于實現線程局部變量。