「Java」這么回答提升30%的通過率,ThreadLocal出現內存泄露嗎?

?考察目的

這是并發編程里面的知識,所以考察的還是技術基礎。

Java基礎是每個公司必然都會考察的,不管你是工作1年還是工作10年。

因為所有的應用框架和中間件,都是在Java基礎上構建出來的。

基本功扎實的人,不僅僅寫的代碼更加可靠,而且學習新技術也更加容易。

?問題解析

ThreadLocal是一個用來解決線程安全性問題的工具。

它相當于讓每個線程都開辟一塊內存空間,用來存儲共享變量的副本。

然后每個線程只需要訪問和操作自己的共享變量副本即可,從而避免多線程競爭同一個共享資源。

它的工作原理很簡單每個線程里面有一個成員變量ThreadLocalMap。

當線程訪問用ThreadLocal修飾的共享數據的時候這個線程就會在自己成員變量ThreadLocalMap里面保存一份數據副本。

key指向ThreadLocal這個引用,并且是弱引用關系,而value保存的是共享數據的副本。

因為每個線程都持有一個副本,所以就解決了線程安全性問題。

image.png

這個問題考察的是內存泄漏,所以必然和對象引用有關系。

ThreadLocal中的引用關系如圖所示,Thread中的成員變量ThreadLocalMap,它里面的可以key指向ThreadLocal這個成員變量,并且它是一個弱引用所謂弱引用,就是說成員變量ThreadLocal允許在這種引用關系存在的情況下,被GC回收。

一旦被回收,key的引用就變成了null,就會導致這個內存永遠無法被訪問,造成內存泄漏。

image.png

那到底ThreadLocal會不會存在內存泄漏呢?

從ThreadLocal本身的設計上來看,是一定存在的。

可能有些小伙伴忍不住想懟我了,如果這個線程被回收了,那線程里面的成員變量都會被回收。

就不會存在內存泄漏問題啊?

這樣理解沒問題,但是在實際應用中,我們一般都是使用線程池,而線程池本身是重復利用的所以還是會存在內存泄漏的問題。

除此之外啊,ThreadLocal為了避免內存泄漏問題,當我們在進行數據的讀寫時,ThreadLocal默認會去嘗試做一些清理動作,找到并清理Entry里面key為null的數據。

但是,它仍然不能完全避免,有同學就問了,那怎么辦啊!!!

有兩個方法可以避免:

  • 每次使用完ThreadLocal以后,主動調用remove()方法移除數據
  • 把ThreadLocal聲明稱全局變量,使得它無法被回收
    ThreadLocal本身的設計并不復雜,要想深入了解,建議大家去看看源碼!

?高手:

我認為,不恰當的使用ThreadLocal,會造成內存泄漏問題。

主要原因是,線程的私有變量ThreadLocalMap里面的key是一個弱引用。

弱引用的特性,就是不管是否存在直接引用關系,當成員ThreadLocal沒用其他的強引用關系的時候,這個對象會被GC回收掉。

從而導致key可能變成null,造成這塊內存永遠無法訪問,出現內存泄漏的問題。

規避內存泄漏的方法有兩個:

  • 通過擴大成員變量ThreadLoca的作用域,避免被GC回收
  • 每次使用完ThreadLocal以后,調用remove方法移除對應的數據
    第一種方法雖然不會造成key為null的現象,但是如果后續線程不再繼續訪問這個key。

也會導致這個內存一直占用不釋放,最后造成內存溢出的問題。

所以我認為最好是在使用完以后調用remove方法移除。

?總結

下次面試的時候遇到這個問題,大家知道怎么回答了嗎?

如果你喜歡我的作品,記得點贊收藏加關注哦!!!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容