ThreadLocal實現原理和使用場景
阿新 • • 發佈:2022-12-13
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類的實現
待更多補充。