<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
在一整個業務邏輯流程中,為了在不同的地方或者不同的方法中使用同一個物件,但是又不想在方法形參中加這個物件,那麼就可以使用ThreadLocal來儲存
ThreadLocal最大的應用場景就是跨方法進行引數傳遞
ThreadLocal可以給每一個執行緒繫結一個變數的副本
ThreadLocal常用的方法其實也就下面幾個
// 返回當前執行緒所對應的執行緒區域性變數。 public T get() {} // 設定當前執行緒的執行緒區域性變數的值。 public void set(T value) {} // 移除,當執行緒結束後,該執行緒thread物件中的區域性變數將在下一次gc時回收,如果顯示的呼叫此方法只是可以加快記憶體回收的速度 // 所以javase開發 普通new Thread()方式中,這個方法並不是必須要呼叫的 // 但是javaWeb開發中就必須顯示呼叫,因為javaweb都是使用的執行緒池,並不是一個使用者端來一個請求,thread執行緒物件用完就刪除,而是會放回執行緒池中。 public void remove() {} // 返回該執行緒區域性變數的一個初始化 // protected方法,顯然是為了讓子類覆蓋而設計的。這個方法在第一次呼叫 get()或 set(Object)時才執行,並且僅執行 1 次 protected T initialValue() {}
在具體使用的時候,我們ThreadLocal物件一定會定義成靜態的,如果不定義成靜態的那麼其他地方如何通過這個ThreadLocal範例去Map中拿資料嘞?
而且如果是多個執行緒儲存一個變數的副本,一個靜態的ThreadLocal也足夠了,因為它是作為多個map中的key存在的
簡單使用案例
/** * @Description: 在一個方法中呼叫set()方法存值,在另一個方法中呼叫get()方法取值 */ public class UseThreadLocalTest { public static ThreadLocal<String> threadLocal = new ThreadLocal<>(); /** * 建立一個執行緒類 */ public static class ThreadTest extends Thread{ private Integer id; ThreadTest(Integer id){ this.id = id; } @Override public void run() { threadLocal.set(Thread.currentThread().getName() + ":" + id); print(); } public void print(){ System.out.println(threadLocal.get()); } } /** * 開三個執行緒 */ public static void main(String[] args) { for (int i = 0; i < 3; i++) { new ThreadTest(i).start(); } } }
// 輸入結果如下
Thread-0:0
Thread-1:1
Thread-2:2
ThreadLocal底層set()和get()方法的原始碼如下
// 存值時 map最終是儲存在當前執行緒Thread t = Thread.currentThread()中的,是thread的一個成員變數 // map的key是當前threadLocal物件範例,value是要存的值 public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); } // 取值時也是也是先從當前執行緒Thread物件中取出map // 然後在從map中根據當前threadLocal物件範例作為key獲取到entry物件 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(); }
為了提高效能,才沒有採用加鎖的方式,而是將map和各個執行緒thread物件進行關聯,這樣就避免了產生執行緒安全問題,也避免了加鎖,提高了效能
我們接下來再來看看ThreadLocalMap
它的實現,它類似於jdk1.7版本的hashmap,底層儲存的是一個Entry物件的陣列,初始容量也是16,存值時先用hash結果和陣列長度取餘得到陣列下標位置,然後判斷是否產生了hash衝突,然後使用開發定址法來處理。根據演演算法的不同又可以分為線性探測再雜湊、二次探測再雜湊、偽隨機探測再雜湊。ThreadLocalMap
它是使用的線性探測再雜湊法,如下所示
private static int nextIndex(int i, int len) { return ((i + 1 < len) ? i + 1 : 0); }
Entry物件中的key
它是一個弱參照,Entry繼承了WeakReference
類,弱參照跟沒參照差不多,GC會直接回收掉,不管記憶體是否足夠都會回收
static class Entry extends WeakReference<ThreadLocal<?>> { Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; } }
上面再介紹ThreadLocal基本使用api方法的時候也提到了,如果只是建立一個普通的執行緒Thread物件,是不會產生記憶體漏失問題的。因為map是儲存在Thread物件中,一個普通執行緒執行完了,那麼這個執行緒的區域性變數也就會被gc回收。
但如果結合到了執行緒池,一個Thread執行緒物件用完後放回執行緒池中,如果這個時候我們程式不顯示的呼叫remove()
方法,那麼就會造成記憶體漏失問題了。
因為Entry物件中的Key的弱參照,但是value還會存在,就會存在map中key為null的value
ThreadLocal 的底層實現中我們可以看見,無論是 get()
、set()
在某些時 候,呼叫了 expungeStaleEntry()
方法用來清除 Entry 中 Key 為 null 的 Value,但是這是不及時的,也不是每次都會執行的,所以一些情況下還是會發生記憶體洩露。
到此這篇關於ThreadLocal導致JVM記憶體漏失原因探究的文章就介紹到這了,更多相關JVM記憶體漏失內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45