### ThreadLocal
ThreadLocal是一個本地線程副本變量工具類。主要用于將私有線程和該線程存放的副本對象做一個映射,各個線程之間的變量互不干擾,在高并發場景下,可以實現無狀態的調用,特別適用于各個線程依賴不通的變量值完成操作的場景
ThreadLocal是為了隔離多個線程數據共享,從根本上就不存在多個線程之間共享資源;
**ThreadLocal的內部結構圖**

**ThreadLocal的核心機制**
* 每個Thread線程內部都有一個Map
* Map里面存儲線程本地對象(key)和線程的變量副本(value)
* Thread內部的Map是由ThreadLocal維護的,由ThreadLocal負責向map獲取和設置線程的變量值
**ThreadLocal類核心方法**
```
public T get()
public void set(T value)
public void remove()
```
* get\(\)方法用于獲取當前線程的副本變量值;
* set\(\)方法用于保存當前線程的副本變量值;
* initialValue\(\)為當前線程初始副本變量值;
* remove\(\)方法移除當前前程的副本變量值;
**ThreadLocalMap**
ThreadLocalMap是ThreadLocal的內部類,沒有實現Map接口,用獨立的方式實現了Map的功能,其內部的Entry也獨立實現

在ThreadLocalMap中,也是用Entry來保存K-V結構數據的。但是Entry中key只能是ThreadLocal對象,這點被Entry的構造方法已經限定死;Entry繼承自WeakReference(弱引用,生命周期只能存活到下次GC前),但只有Key是弱引用類型的,Value并非弱引用
```
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
```
**Hash沖突**
和HashMap的最大的不同在于,ThreadLocalMap結構非常簡單,沒有next引用,也就是說ThreadLocalMap中解決Hash沖突的方式并非鏈表的方式,而是采用線性探測的方式,所謂線性探測,就是根據初始key的hashcode值確定元素在table數組中的位置,如果發現這個位置上已經有其他key值的元素被占用,則利用固定的算法尋找一定步長的下個位置,依次判斷,直至找到能夠存放的位置
ThreadLocalMap解決Hash沖突的方式就是簡單的步長加1或減1,尋找下一個相鄰的位置
```
/**
* Increment i modulo len.
*/
private static int nextIndex(int i, int len) {
return ((i + 1 < len) ? i + 1 : 0);
}
/**
* Decrement i modulo len.
*/
private static int prevIndex(int i, int len) {
return ((i - 1 >= 0) ? i - 1 : len - 1);
}
```
### 【知識點】
由于ThreadLocalMap的key是弱引用,而Value是強引用。這就導致了一個問題,ThreadLocal在沒有外部對象強引用時,發生GC時弱引用Key會被回收,而Value不會回收,如果創建ThreadLocal的線程一直持續運行,那么這個Entry對象中的value就有可能一直得不到回收,發生內存泄露
如何避免泄漏
既然Key是弱引用,那么我們要做的事,就是在調用ThreadLocal的get\(\)、set\(\)方法時完成后再調用remove方法,將Entry節點和Map的引用關系移除,這樣整個Entry對象在GC Roots分析后就變成不可達了,下次GC的時候就可以被回收
- 簡介
- 概述
- 進程vs線程
- 資源限制
- 有關并行的兩個定律
- 線程同步和阻塞
- 線程阻塞
- 線程的特性
- 守護線程
- 線程異常
- Thread
- 線程狀態
- 線程中斷
- wait¬ify
- suspend&resume
- join&yield
- notify¬ifyAll
- Thread.sleep
- 線程任務
- Runnable
- Callable
- Future模式
- FutureTask
- 線程實現方式
- 內核線程實現
- 用戶線程實現
- 混合實現
- Java線程的實現
- java與協程
- 纖程-Fiber
- 線程調度
- 多線程協作方式
- 阻塞
- 放棄
- 休眠
- 連接線程
- 線程估算公式
- 線程活躍性
- 死鎖
- 線程安全性
- 對象的發布與逸出
- 構造方法溢出
- 線程封閉
- 對象的可變性
- 原子性
- 原子操作
- CPU原子操作原理
- 總線鎖
- 緩存鎖
- JAVA如何實現原子操作
- long和double讀寫操作原子性
- Adder和Accumulator
- 線程性能
- 同步工具類
- 閉鎖
- CountDownLatch
- FutureTask
- 信號量
- 柵欄
- CyclicBarrier
- Exchanger
- 并發編程
- volatile
- synchronized
- 無鎖
- 偏向鎖
- 輕量級鎖
- 鎖的優缺點對比
- 鎖升級
- 鎖消除
- Monitor
- synchronized語法
- Mutex Lock
- synchronized實踐問題
- synchronized&ReentrantLock
- Lock
- ReentrantLock
- Condition
- 讀寫鎖
- ReadWriteLock
- StampedLock
- 線程池
- Executor
- ExecutorService
- Executors
- ThreadPoolExecutor
- RejectedExecutionHandler
- ThreadFactory
- 線程池大小公式
- 動態調整線程池大小
- Fork/Join框架
- ForkJoinPool
- CompletableFuture
- JUC并發工具包
- LockSupport
- 延時任務與周期任務
- Timer
- TimerTask
- 異構任務并行化
- CompletionService
- volatile和synchronized比較
- 鎖優化
- 鎖相關概念
- 悲觀鎖(排它鎖)
- 樂觀鎖
- 自旋鎖
- 樂觀鎖vs悲觀鎖
- JVM鎖優化-鎖消除
- ThreadLocal
- InheritableThreadLocal
- TransmittableThreadLocal
- ThreadLocalRandom
- 無鎖
- AtomicInteger
- Unsafe
- AtomicReference
- AtomicStampedReference
- AtomicIntegerArray
- AtomicIntegerFieldUpdater
- 無鎖Vector
- LongAdder
- LongAccumulator
- 常見鎖類型
- 悲觀鎖&獨占鎖
- 樂觀鎖
- 樂觀鎖vs悲觀鎖
- 自旋鎖vs適應性自旋鎖
- 公平鎖vs非公平鎖
- 可重入鎖vs非可重入鎖
- 獨享鎖vs共享鎖
- 互斥鎖
- CAS
- AQS介紹
- AQS深入剖析
- AQS框架
- AQS核心思想
- AQS數據結構
- 同步狀態State
- ReentrantLock vs AQS
- AQS與ReentrantLock的關聯
- ReentrantLock具體實現
- 線程加入等待隊列
- 等待隊列中線程出隊列時機
- 如何解鎖
- 中斷恢復后的執行流程
- ReentrantLock的可重入應用
- JUC中的應用場景
- 自定義同步工具
- CLH鎖
- 并發框架
- Akka
- Disruptor-無鎖緩存框架
- 常見面試題
- 兩個線程交替打印A和B
- 附錄