20191116 ThreadLocal原始碼解析

2021-09-29 16:35:50 字數 2699 閱讀 8074

threadlocal是用來儲存執行緒的本地資料的。

threadlocal的設計算是十分巧妙的。

每乙個執行緒thread持有threadlocalmap, threadlocalmap是threadlocal下的乙個內部靜態類。threadlocalmap並沒有繼承map, 而是持有了乙個entry的table。entry的key是threadlocal (弱引用), value是儲存的值。

來看一下threadlocal的set方法:

public void set(t value)
跟進,看一下threadlocalmap的set方法:

private void set(threadlocal> key, object value) 

//如果當前這個的 entry 是乙個陳舊entry(有物件但是k == null),

//那就呼叫 replacestaleentry(key, value, i);將資料儲存進去,並結束

if (k == null)

}tab[i] = new entry(key, value);

int sz = ++size;

// 清除部分的陳舊entry,如果清除不成功,

//並且大於等於負載閾值 threshold (當前size的2/3)的時候就會 rehash

if (!cleansomeslots(i, sz) && sz >= threshold)

rehash();

}

先來看下replacestaleentry這個方法:

private void replacestaleentry(threadlocal> key, object value,

int staleslot)

//如果在查詢過程中還未發現髒entry,那麼就以當前位置作為cleansomeslots的起點

if (k == null && slottoexpunge == staleslot)

slottoexpunge = i;

}// 如果在查詢過程中沒有找到可以覆蓋的entry,則將新的entry插入在髒entry

tab[staleslot].value = null;

tab[staleslot] = new entry(key, value);

// 如果找到了,清理

if (slottoexpunge != staleslot)

cleansomeslots(expungestaleentry(slottoexpunge), len);

}

作者認為在髒key的附近髒key是聚集的,那麼在當前key是存在key為null,value不為null的情況下,向前尋找到key不為null的節點,然後向後遍歷進行區域性清理髒key。

這樣不用進行遍歷全部資料,同時也可以進行一部分的髒key的清理,但終究出現記憶體洩露時,節點越來越多,慢慢就清理不過來了。

private boolean cleansomeslots(int i, int n) 

} while ( (n >>>= 1) != 0);

return removed;

}

可以看到, cleansomeslots這個看上去是log(n)的時間複雜度。但需要主要的是:一旦檢查到髒entry(key為null),n又會重新賦值為table的長度。

}相比於set()方法,get()方法就簡單很多了。

當我們呼叫threadlocal的get方法時,當table[i]不是和所要找的key相同的話,會繼續通過threadlocalmap的

getentryaftermiss方法向後環形去找:

public t get() 

}return setinitialvalue();

}

private entry getentry(threadlocal> key)
private entry getentryaftermiss(threadlocal> key, int i, entry e) 

return null;

}

private void remove(threadlocal> key) }}

我們知道threadlocalmap.entry的key是乙個弱引用。這就存在記憶體洩漏的問題,當key被**掉的時候,value一直得不到清除。

那為什麼仍要採用弱引用呢?

如果採用強引用,將threadlocal置為null的時候,因為threadlocalmap還強引用著threadlocal,造成threadlocal無法被**。

相比之下,採用弱引用,配合著上面get(), remove(), set()方法的**,是可以有效的解決記憶體洩漏的問題的。但前提是要使用這些方法!

ThreadLocal原始碼理解

threadlocal其實原理是建立了多份相同資料儲存在堆記憶體上,每個執行緒的thread類裡有threadlocal.threadlocalmap threadlocals的屬性來指向存位置,所以每個執行緒修改都不會影響到其他執行緒的資料 首先說下下面用到的東西 threadlocalmap為t...

ThreadLocal原始碼分析

在理解handler looper之前,先來說說threadlocal這個類,聽名字好像是乙個本地執行緒的意思,實際上它並不是乙個thread,而是提供乙個與執行緒有關的區域性變數功能,每個執行緒之間的資料互不影響。我們知道使用handler的時候,每個執行緒都需要有乙個looper物件,那麼and...

ThreadLocal 原始碼解讀

在正式讀 前先簡單介紹threadlocal的實現方式。每個執行緒都會有乙個threadlocalmap,只有在使用到threadlocal的時候才會初始化threadlocalmap。需要儲存的物件t會被放到entry裡面儲存在threadlocalmap的陣列中,entry是乙個鍵值對的資料結構...