Java並發編程:深入剖析ThreadLocal (總結)

來源:互聯網
上載者:User

標籤:==   phi   ssi   記憶體回收   基本   使用情境   而在   new   http   

 

 

問答形式總結: 1、 ThreadLocal類的作用

  ThreadLocal的作用是提供線程內的局部變數,這種變數在多線程環境下訪問時能夠保證各個線程裡變數的獨立性。

  ThreadLocal用於儲存某個線程共用變數:對於同一個static ThreadLocal,不同線程只能從中get,set,remove自己的變數,而不會影響其他線程的變數。

  1、ThreadLocal.get: 擷取ThreadLocal中當前線程共用變數的值。

  2、ThreadLocal.set: 設定ThreadLocal中當前線程共用變數的值。

  3、ThreadLocal.remove: 移除ThreadLocal中當前線程共用變數的值。

  4、ThreadLocal.initialValue: ThreadLocal沒有被當前線程賦值時或當前線程剛調用remove方法後調用get方法,返回此方法值。

 

2、 ThreadLocal原理,ThreadLocal是如何?的?

      首先,在每個線程Thread內部有一個ThreadLocal.ThreadLocalMap類型的成員變數threadLocals,這個threadLocals就是用來儲存實際的變數副本的,索引值為當前ThreadLocal變數,value為變數副本(即T類型的變數)。

  初始時,在Thread裡面,threadLocals為空白,當通過ThreadLocal變數調用get()方法或者set()方法,就會對Thread類中的threadLocals進行初始化,並且以當前ThreadLocal變數為索引值,以ThreadLocal要儲存的副本變數為value,存到threadLocals。

  然後在當前線程裡面,如果要使用副本變數,就可以通過get方法在threadLocals裡面尋找。

       總結一下:

  1)實際的通過ThreadLocal建立的副本是儲存在每個線程自己的threadLocals中的;

  2)為何threadLocals的類型ThreadLocalMap的索引值為ThreadLocal對象,因為每個線程中可有多個threadLocal變數,就像上面代碼中的longLocal和stringLocal;

  3)在進行get之前,必須先set,否則會報null 指標異常;

      如果想在get之前不需要調用set就能正常訪問的話,必須重寫initialValue()方法。

    因為在上面的程式碼分析過程中,我們發現如果沒有先set的話,即在map中尋找不到對應的儲存,則會通過調用setInitialValue方法返回i,而在setInitialValue方法中,有一個語句是T value = initialValue(), 而預設情況下,initialValue方法返回的是null。

3、 ThreadLocal的使用情境

最常見的ThreadLocal使用情境為 用來解決 資料庫連接、Session管理等。

  如:

private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>() {    public Connection initialValue() {        return DriverManager.getConnection(DB_URL);    }};     public static Connection getConnection() {    return connectionHolder.get();   }

 下面這段代碼摘自:

  http://www.iteye.com/topic/103804

private static final ThreadLocal threadSession = new ThreadLocal(); public static Session getSession() throws InfrastructureException {    Session s = (Session) threadSession.get();    try {        if (s == null) {            s = getSessionFactory().openSession();            threadSession.set(s);        }    } catch (HibernateException ex) {        throw new InfrastructureException(ex);    }    return s;}

 

4、 常說的ThreadLocal記憶體流失問題:

static class Entry extends WeakReference<ThreadLocal<?>> { /** The value associated with this ThreadLocal. */ Object value;   Entry(ThreadLocal<?> k, Object v) {    super(k);    value = v;   } }

 

        從上面源碼可以看出,ThreadLocalMap使用ThreadLocal的弱引用作為Entry的key,如果一個ThreadLocal沒有外部強引用來引用它,下一次系統GC時,這個ThreadLocal必然會被回收,這樣一來,ThreadLocalMap中就會出現key為null的Entry,就沒有辦法訪問這些key為null的Entry的value。

        我們上面介紹的get、set、remove等方法中,都會對key為null的Entry進行清除(expungeStaleEntry方法,將Entry的value清空,等下一次記憶體回收時,這些Entry將會被徹底回收)。

        但是如果當前線程一直在運行,並且一直不執行get、set、remove方法,這些key為null的Entry的value就會一直存在一條強引用練:Thread Ref -> Thread -> ThreadLocalMap -> Entry -> value,導致這些key為null的Entry的value永遠無法回收,造成記憶體流失。  

   如何避免記憶體流失?

    為了避免這種情況,我們可以在使用完ThreadLocal後,手動調用remove方法,以避免出現記憶體流失。

 

5、其他總結

總結:
  1. 每個線程都有一個ThreadLocalMap 類型的 threadLocals 屬性。
  2. ThreadLocalMap 類相當於一個Map,key 是 ThreadLocal 本身,value 就是我們的值。
  3. 當我們通過 threadLocal.set(new Integer(123)); ,我們就會在這個線程中的 threadLocals 屬性中放入一個索引值對,key 是 這個 threadLocal.set(new Integer(123))的threadlocal,value 就是值new Integer(123)。
  4. 當我們通過 threadlocal.get() 方法的時候,首先會根據這個線程得到這個線程的 threadLocals 屬性,然後由於這個屬性放的是索引值對,我們就可以根據鍵 threadlocal 拿到值。 注意,這時候這個鍵 threadlocal 和 我們 set 方法的時候的那個鍵 threadlocal 是一樣的,所以我們能夠拿到相同的值。
  5. ThreadLocalMap 的get/set/remove方法跟HashMap的內部實現都基本一樣,通過 "key.threadLocalHashCode & (table.length - 1)" 運算式計算得到我們想要找的索引位置,如果該索引位置的索引值對不是我們要找的,則通過nextIndex方法計算下一個索引位置,直到找到目標索引值對或者為空白。
  6. hash衝突:在HashMap中相同索引位置的元素以鏈表形式儲存在同一個索引位置;而在ThreadLocalMap中,沒有使用鏈表的資料結構,而是將(當前的索引位置+1)對length模數的結果作為相同索引元素的位置:源碼中的nextIndex方法,可以表達成如下公式:如果i為當前索引位置,則下一個索引位置 = (i + 1 < len) ? i + 1 : 0。

—————END—————

 

參考文章:1、 Java並發:ThreadLocal詳解 (JoonWhee)

2、Java並發編程:深入剖析ThreadLocal (海子)

 

 

Java並發編程:深入剖析ThreadLocal (總結)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.