日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java并发编程实战~ThreadLocal

發布時間:2024/7/23 java 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java并发编程实战~ThreadLocal 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

ThreadLocal 的使用方法

static class SafeDateFormat {// 定義 ThreadLocal 變量static final ThreadLocal<DateFormat>tl = ThreadLocal.withInitial(()-> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));static DateFormat get(){return tl.get();} }// 不同線程執行下面代碼 // 返回的 df 是不同的 DateFormat df = SafeDateFormat.get();

ThreadLocal 的工作原理

錯誤的實現方案

?

class MyThreadLocal<T> {Map<Thread, T> locals = new ConcurrentHashMap<>();// 獲取線程變量 T get() {return locals.get(Thread.currentThread());}// 設置線程變量void set(T t) {locals.put(Thread.currentThread(), t);} }

JDK實現方案

????????Thread 這個類內部有一個私有屬性 threadLocals,其類型就是 ThreadLocalMap,ThreadLocalMap 的 Key 是ThreadLocal。

?

class Thread {// 內部持有 ThreadLocalMapThreadLocal.ThreadLocalMap threadLocals; }class ThreadLocal<T>{public T get() {// 首先獲取線程持有的//ThreadLocalMapThreadLocalMap map = Thread.currentThread().threadLocals;// 在 ThreadLocalMap 中// 查找變量Entry e = map.getEntry(this);return e.value; }static class ThreadLocalMap{// 內部是數組而不是 MapEntry[] table;// 根據 ThreadLocal 查找 EntryEntry getEntry(ThreadLocal key){// 省略查找邏輯}//Entry 定義static class Entry extends WeakReference<ThreadLocal>{Object value;}} }

????????ThreadLocal 僅僅是一個代理工具類,內部并不持有任何與線程相關的數據,所有和線程相關的數據都存儲在 Thread 里面,這樣的設計容易理解。而從數據的親緣性上來講,ThreadLocalMap 屬于 Thread 也更加合理。

????????當然還有一個更加深層次的原因,那就是不容易產生內存泄露。在我們的設計方案中,ThreadLocal 持有的 Map 會持有 Thread 對象的引用,這就意味著,只要 ThreadLocal對象存在,那么 Map 中的 Thread 對象就永遠不會被回收。ThreadLocal 的生命周期往往都比線程要長,所以這種設計方案很容易導致內存泄露。而 Java 的實現中 Thread 持有ThreadLocalMap,而且 ThreadLocalMap 里對 ThreadLocal 的引用還是弱引用(WeakReference),所以只要 Thread 象可以被回收,那么 ThreadLocalMap 就能被回收。Java 的這種實現方案雖然看上去復雜一些,但是更加安全。

ThreadLocal 與內存泄露

????????在線程池中使用 ThreadLocal 為什么可能導致內存泄露呢?原因就出在線程池中線程的存活時間太長,往往都是和程序同生共死的,這就意味著 Thread 持有的 ThreadLocalMap一直都不會被回收,再加上 ThreadLocalMap 中的 Entry 對 ThreadLocal 是弱引用(WeakReference),所以只要 ThreadLocal 結束了自己的生命周期是可以被回收掉的。但是 Entry 中的 Value 卻是被 Entry 強引用的,所以即便 Value 的生命周期結束了,Value 也是無法被回收的,從而導致內存泄露。

????????那在線程池中,我們該如何正確使用 ThreadLocal 呢?其實很簡單,既然 JVM 不能做到自動釋放對 Value 的強引用,那我們手動釋放就可以了。

ExecutorService es; ThreadLocal tl; es.execute(()->{//ThreadLocal 增加變量tl.set(obj);try {// 省略業務邏輯代碼}finally {// 手動清理 ThreadLocal tl.remove();} });

InheritableThreadLocal 與繼承性

????????通過 ThreadLocal 創建的線程變量,其子線程是無法繼承的。也就是說你在線程中通過
ThreadLocal 創建了線程變量 V,而后該線程創建了子線程,你在子線程中是無法通過
ThreadLocal 來訪問父線程的線程變量 V 的。

????????如果你需要子線程繼承父線程的線程變量,那該怎么辦呢?其實很簡單,Java 提供了
InheritableThreadLocal 來支持這種特性。

????????不過,不建議你在線程池中使用 InheritableThreadLocal,不僅僅是因為它具有ThreadLocal 相同的缺點——可能導致內存泄露,更重要的原因是:線程池中線程的創建是動態的,很容易導致繼承關系錯亂,如果你的業務邏輯依賴 InheritableThreadLocal,那么很可能導致業務邏輯計算錯誤,而這個錯誤往往比內存泄露更要命。

總結

以上是生活随笔為你收集整理的Java并发编程实战~ThreadLocal的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。