1. 程式人生 > 其它 >ThreadLocal實現原理和使用場景

ThreadLocal實現原理和使用場景

ThreadLocal是執行緒本地變數,每個執行緒中都存在副本。

實現原理:

每個執行緒中都有一個ThreadLocalMap,而ThreadLocalMap中的key即是ThreadLocal。

 記憶體洩漏:

ThreadLocal變數儲存在棧記憶體中,對應物件儲存在堆記憶體中,這個指向是強引用關係。

同樣,ThreadLocalMap變數儲存在棧記憶體中,對應物件key-value儲存在堆記憶體中,也是強引用關係。同時map中的key也指向了threadlocal。

如果ThreadLocal變數被置為空,但是map仍存在引用,會導致堆中的物件無法釋放,java已將map中的key優化為弱引用(WeakReference)。

但是value本身也存在強引用的關係,value並不會被釋放,所以依然存在記憶體洩漏問題。

解決方法是,手動呼叫threadlocal的remove方法。

使用:

 1 public class Main {
 2     private static ThreadLocal<Integer> tl = new ThreadLocal<>();
 3     public static void main(String[] args) throws InterruptedException{
 4         CountDownLatch c = new CountDownLatch(1);
5 ThreadPoolExecutor tpe = new ThreadPoolExecutor(10, 20, 60L, TimeUnit.SECONDS, 6 new ArrayBlockingQueue<>(3)); 7 tpe.execute(new Runnable() { 8 @Override 9 public void run() { 10 System.out.println(Thread.currentThread().getName());
11 System.out.println(tl.get()); 12 tl.set(1); 13 System.out.println(tl.get()); 14 tl.remove(); 15 c.countDown(); 16 } 17 }); 18 tpe.execute(new Runnable() {//模擬 19 @Override 20 public void run() { 21 try{c.await();}catch (InterruptedException e){};//讓第一個執行緒先執行 22 System.out.println(Thread.currentThread().getName()); 23 System.out.println(tl.get()); 24 tl.set(2); 25 System.out.println(tl.get()); 26 tl.remove(); 27 } 28 }); 29 tpe.shutdown(); 30 } 31 }

應用場景:

1,Spring多資料來源配置的切換;

2,Spring事務註解的實現;

3,日誌框架slf4j中的MDC類的實現

待更多補充。