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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

揭秘ThreadLocal

發布時間:2024/9/21 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 揭秘ThreadLocal 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

ThreadLocal是開發中最常用的技術之一,也是面試重要的考點。本文將由淺入深,介紹ThreadLocal的使用方式、實現原理、內存泄漏問題以及使用場景。

ThreadLocal作用

在并發編程中時常有這樣一種需求:每條線程都需要存取一個同名變量,但每條線程中該變量的值均不相同。

如果是你,該如何實現上述功能?常規的思路如下: 使用一個線程共享的Map<Thread,Object>,Map中的key為線程對象,value即為需要存儲的值。那么,我們只需要通過map.get(Thread.currentThread())即可獲取本線程中該變量的值。

這種方式確實可以實現我們的需求,但它有何缺點呢?——答案就是:需要同步,效率低!

由于這個map對象需要被所有線程共享,因此需要加鎖來保證線程安全性。當然我們可以使用java.util.concurrent.*包下的ConcurrentHashMap提高并發效率,但這種方法只能降低鎖的粒度,不能從根本上避免同步鎖。而JDK提供的ThreadLocal就能很好地解決這一問題。下面來看看ThreadLocal是如何高效地實現這一需求的。

如何使用ThreadLocal

在介紹ThreadLocal原理之前,首先簡單介紹一下它的使用方法。

public class Main{private ThreadLocal<Integer> threadLocal = new ThreadLocal<>();public void start() {for (int i=0; i<10; i++) {new Thread(new Runnable(){@overridepublic void run(){threadLocal.set(i);threadLocal.get();threadLocal.remove();}}).start();}} } 復制代碼
  • 首先我們需要創建一個線程共享的ThreadLocal對象,該對象用于存儲Integer類型的值;
  • 然后在每條線程中可以通過如下方法操作ThreadLocal:
    • set(obj):向當前線程中存儲數據
    • get():獲取當前線程中的數據
    • remove():刪除當前線程中的數據

ThreadLocal的使用方法非常簡單,關鍵在于它背后的實現原理。回到上面的問題:ThreadLocal究竟是如何避免同步鎖,從而保證讀寫的高效?

ThreadLocal實現原理

ThreadLocal的內部結構如下圖所示:

ThreadLocal并不維護ThreadLocalMap,并不是一個存儲數據的容器,它只是相當于一個工具包,提供了操作該容器的方法,如get、set、remove等。而ThreadLocal內部類ThreadLocalMap才是存儲數據的容器,并且該容器由Thread維護。

每一個Thread對象均含有一個ThreadLocalMap類型的成員變量threadLocals,它存儲本線程中所有ThreadLocal對象及其對應的值。

ThreadLocalMap由一個個Entry對象構成,Entry的代碼如下:

static class Entry extends WeakReference<ThreadLocal<?>> {Object value;Entry(ThreadLocal<?> k, Object v) {super(k);value = v;} } 復制代碼

Entry繼承自WeakReference<ThreadLocal<?>>,一個Entry由ThreadLocal對象和Object構成。由此可見,Entry的key是ThreadLocal對象,并且是一個弱引用。當沒指向key的強引用后,該key就會被垃圾收集器回收。

那么,ThreadLocal是如何工作的呢?下面來看set和get方法。

public void set(T value) {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null)map.set(this, value);elsecreateMap(t, value); }public T get() {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null) {ThreadLocalMap.Entry e = map.getEntry(this);if (e != null) {@SuppressWarnings("unchecked")T result = (T)e.value;return result;}}return setInitialValue(); }ThreadLocalMap getMap(Thread t) {return t.threadLocals; } 復制代碼

當執行set方法時,ThreadLocal首先會獲取當前線程對象,然后獲取當前線程的ThreadLocalMap對象。再以當前ThreadLocal對象為key,將值存儲進ThreadLocalMap對象中。

get方法執行過程類似。ThreadLocal首先會獲取當前線程對象,然后獲取當前線程的ThreadLocalMap對象。再以當前ThreadLocal對象為key,獲取對應的value。

由于每一條線程均含有各自私有的ThreadLocalMap容器,這些容器相互獨立互不影響,因此不會存在線程安全性問題,從而也無需使用同步機制來保證多條線程訪問容器的互斥性。

為何要使用弱引用?

對弱引用不了解的同學可以參考筆者的另一篇文章:http://blog.csdn.net/u010425776/article/details/50760053。

Java設計之初的一大宗旨就是——弱化指針。 Java設計者希望通過合理的設計簡化編程,讓程序員無需處理復雜的指針操作。然而指針是客觀存在的,在目前的Java開發中也不可避免涉及到“指針操作”。如:

Object a = new Object(); 復制代碼

上述代碼創建了一個強引用a,只要強引用存在,垃圾收集器是不會回收該對象的。如果該對象非常龐大,那么為了節約內存空間,在該對象使用完成后,我們需要手動拆除該強引用,如下面代碼所示:

a = null; 復制代碼

此時,指向該對象的強引用消除了,垃圾收集器便可以回收該對象。但在這個過程中,仍然需要程序員處理指針。為了弱化指針這一概念,弱引用便出現了,如下代碼創建了一個Person類型的弱引用:

WeakReference<Person> wr = new WeakReference<Person>(new Person()); 復制代碼

此時程序員不用再關注指針,只要沒有強引用指向Person對象,垃圾收集器每次運行都會自動將該對象釋放。

那么,ThreadLocalMap中的key使用弱引用的原因也是如此。當一條線程中的ThreadLocal對象使用完畢,沒有強引用指向它的時候,垃圾收集器就會自動回收這個Key,從而達到節約內存的目的。

那么,問題又來了——這會導致內存泄漏問題!

ThreadLocal的內存泄漏問題

在ThreadLocalMap中,只有key是弱引用,value仍然是一個強引用。當某一條線程中的ThreadLocal使用完畢,沒有強引用指向它的時候,這個key指向的對象就會被垃圾收集器回收,從而這個key就變成了null;然而,此時value和value指向的對象之間仍然是強引用關系,只要這種關系不解除,value指向的對象永遠不會被垃圾收集器回收,從而導致內存泄漏!

不過不用擔心,ThreadLocal提供了這個問題的解決方案。

每次操作set、get、remove操作時,ThreadLocal都會將key為null的Entry刪除,從而避免內存泄漏。

那么問題又來了,如果一個線程運行周期較長,而且將一個大對象放入LocalThreadMap后便不再調用set、get、remove方法,此時該仍然可能會導致內存泄漏。

這個問題確實存在,沒辦法通過ThreadLocal解決,而是需要程序員在完成ThreadLocal的使用后要養成手動調用remove的習慣,從而避免內存泄漏。

ThreadLocal的使用場景

Web系統Session的存儲就是ThreadLocal一個典型的應用場景。

Web容器采用線程隔離的多線程模型,也就是每一個請求都會對應一條線程,線程之間相互隔離,沒有共享數據。這樣能夠簡化編程模型,程序員可以用單線程的思維開發這種多線程應用。

當請求到來時,可以將當前Session信息存儲在ThreadLocal中,在請求處理過程中可以隨時使用Session信息,每個請求之間的Session信息互不影響。當請求處理完成后通過remove方法將當前Session信息清除即可。

與50位技術專家面對面20年技術見證,附贈技術全景圖

總結

以上是生活随笔為你收集整理的揭秘ThreadLocal的全部內容,希望文章能夠幫你解決所遇到的問題。

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

主站蜘蛛池模板: 国产人妖在线 | 成年人av网站 | 捆绑束缚调教 | 国产精品一区二区人妻喷水 | 波多野结衣电影在线播放 | 一本一道久久综合狠狠老精东影业 | 在线观看成年人视频 | 国产在线最新 | 日本三级吃奶头添泬 | 久久视频在线免费观看 | 国产精品毛片一区二区在线看舒淇 | 双性受孕h堵精大肚生子 | 欧美激情精品 | 高潮毛片又色又爽免费 | 中国女人毛片 | 亚洲二区av | 在线观看视频国产 | 少妇熟女视频一区二区三区 | 超碰在线免费 | 亚洲福利一区 | av色图 | 制服.丝袜.亚洲.中文.综合 | 四虎影视成人永久免费观看亚洲欧美 | 中文字幕日韩一级 | 国产精品入口麻豆九色 | 亚洲最新av网站 | 亚洲精品国产精品国自产观看浪潮 | jizz日本大全 | 国产成人无码精品 | 欧美一级专区免费大片 | 伊人久操| 国产一区二区免费在线观看 | 成人1区2区3区 | 国产7777777 | 91国内揄拍国内精品对白 | 一本在线免费视频 | 精品久久ai | 亚洲高清一区二区三区 | 最近日韩中文字幕中文 | 16—17女人毛片 | 美女自拍偷拍 | 国产模特av私拍大尺度 | 一区二区三区四区av | 人妻丰满熟妇av无码区 | 国产精品爽爽 | 99久久99久久免费精品蜜臀 | 99re6在线观看 | 丝袜 中出 制服 人妻 美腿 | 中文字幕乱码在线人视频 | 日韩在线播放一区 | 欧美天堂视频 | 日韩欧美在线视频 | youjizz韩国| 国产区网址 | 青青视频网 | 人妻体内射精一区二区 | 日本三级中国三级99人妇网站 | 少妇免费视频 | 岛国av免费在线观看 | 国产精品一二三四 | 新天堂在线 | 免费男女乱淫真视频免费播放 | 人人综合网 | 台湾av在线播放 | 午夜影剧院 | 欧美激情在线狂野欧美精品 | 在线免费观看日韩av | 午夜影院日本 | 在线观看免费www | 国产一区二区三区在线观看免费 | 天天做天天摸天天爽天天爱 | 手机在线精品视频 | 国产美女黄网站 | 少妇婷婷| 精品不卡一区 | 久久成人18免费观看 | 天天摸天天做天天爽 | 成人免费在线视频 | 欧美精品免费一区二区 | 中文字幕乱码免费 | 国产精品一线天 | 向日葵视频在线 | 91人人草| 欧美精品一区二区在线播放 | 黄色网址在线视频 | 少妇饥渴放荡91麻豆 | 麻豆蜜桃av | 1769国产精品视频 | 欧美一区二区三区久久久 | 男人靠女人免费视频网站 | 娇妻之欲海泛舟无弹窗笔趣阁 | 日韩精品成人免费观看视频 | 精品视频大全 | 玖玖视频网 | 国产又粗又猛又爽视频 | 波多野结衣高清电影 | 黄色av网站在线免费观看 | 欧美日韩一区电影 | 日本一区二区三区久久久久 |