java基礎-ThreadLocal

來源:互聯網
上載者:User

標籤:als   oca   封裝   工作   它的   final   ref   定義   turn   

來聊一下ThreadLocal的實現原理和它的記憶體流失問題

 

首先來看一個官方樣本,這裡構造了一個ThreadId類,其作用是在每個線程中儲存各自的id,此id全域唯一,通過get可以擷取id。

 1     private static class ThreadId { 2         // Atomic integer containing the next thread ID to be assigned 3         private static final AtomicInteger nextId = new AtomicInteger(1); 4         // Thread local variable containing each thread‘s ID 5         private static final ThreadLocal<Integer> threadId = new ThreadLocal<Integer>() { 6             @Override 7             protected Integer initialValue() { 8                 return nextId.getAndIncrement(); 9             }10         };11         // Returns the current thread‘s unique ID, assigning it if necessary12         public static int get() {13             return threadId.get();14         }15     }

 

ThreadLocal的構造器是一個空函數,new一個ThreadLocal執行個體時,唯一的操作就是對threadLocalHashCode的初始化,很明顯這是一個hash值,猜測後續會用到map了。

1 private final int threadLocalHashCode = nextHashCode();

 

再來看調用get時,發生了什麼

/**     * Returns the value in the current thread‘s copy of this     * thread-local variable.  If the variable has no value for the     * current thread, it is first initialized to the value returned     * by an invocation of the {@link #initialValue} method.     *     * @return the current thread‘s value of this thread-local     */    public T get() {        Thread t = Thread.currentThread();        //Thread中有一個ThreadLocalMap類型的執行個體欄位,獲得當前線程的threadLocalMap,其實就是返回t.threadLocals        ThreadLocalMap map = getMap(t);        if (map != null) {            //以當前ThreadLocal執行個體為key,擷取entry            ThreadLocalMap.Entry e = map.getEntry(this);            if (e != null) {                @SuppressWarnings("unchecked")                //得到entry中的value                T result = (T)e.value;                return result;            }        }        //如果當前線程的threadLocalMap為null,或者當前threadLocal還未插入threadLocalMap,則進行相應初始化工作,無非就是初始化map、調用自訂的initialValue方法、將initialValue傳回值封裝成entry插入map        return setInitialValue();     }

 

看一下map的構造

 1     static class ThreadLocalMap { 2         ...... 3         static class Entry extends WeakReference<ThreadLocal<?>> { 4             /** The value associated with this ThreadLocal. */ 5             Object value; 6  7             Entry(ThreadLocal<?> k, Object v) { 8                 //注意,這裡key被封裝成了一個WeakReference 9                 super(k);10                 value = v;11             }12         }13         ......14         private Entry[] table;15         ......16         private Entry getEntry(ThreadLocal<?> key) {17             //threadLocalHashCode在ThreadLocal初始化時就已產生,全域唯一。這裡18             int i = key.threadLocalHashCode & (table.length - 1);19             Entry e = table[i];20             if (e != null && e.get() == key)//e.get()即從WeakReference中取得threadLocal21                 return e;22             else23                 //有意思,一般的hash表都是使用一個鏈式結構來解決hash衝突,而這裡當hash衝突時進行線性探測24                 return getEntryAfterMiss(key, i, e);25         }26         ......27     }

 

問題來了,為什麼entry中的key要封裝成WeakReference呢?

設想,當我們不再需要threadLocal了,以前例來說就是置ThreadId中類變數threadId為null(假設threadId不是final,也沒有被其他引用),而Thread類中的threadLocalMap中仍然持有threadId的引用,這就會產生記憶體流失。將threadLocal封裝成WeakReference作為key儲存,當threadId為null時,該threadLocal在gc時就會被回收,但此時value還在,ThreadLocal會在進行其他動作時刪除key為null的value。這確實存在一種記憶體流失隱患,如果之後不在進行ThreadLocal操作,就真釋放不掉value了。通常我們需要被聲明為ThreadLocal的變數,在運行期間都是不期望它被回收的,所以我們通常會將其聲明為static final,如果有回收的需求,也請使用ThreadLocal的remove進行顯示釋放。

 

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.