-
ThreadLocal源碼之回收HashMap空間
remove操作,移除ThreadLocal實例中的數(shù)據(jù)并清理失效的數(shù)據(jù)
/** ?*?Remove?the?entry?for?key. ?*/ private?void?remove(ThreadLocal<?>?key)?{ ????Entry[]?tab?=?table; ????int?len?=?tab.length; ????int?i?=?key.threadLocalHashCode?&?(len-1); ????for?(Entry?e?=?tab[i]; ?????????e?!=?null; ?????????e?=?tab[i?=?nextIndex(i,?len)])?{ ????????if?(e.get()?==?key)?{ ????????????e.clear(); ????????????expungeStaleEntry(i); ????????????return; ????????} ????} }
/** ?*?Expunge?a?stale?entry?by?rehashing?any?possibly?colliding?entries ?*?lying?between?staleSlot?and?the?next?null?slot.??This?also?expunges ?*?any?other?stale?entries?encountered?before?the?trailing?null.??See ?*?Knuth,?Section?6.4 ?* ?*?@param?staleSlot?index?of?slot?known?to?have?null?key ?*?@return?the?index?of?the?next?null?slot?after?staleSlot ?*?(all?between?staleSlot?and?this?slot?will?have?been?checked ?*?for?expunging). ?*/ private?int?expungeStaleEntry(int?staleSlot)?{ ????Entry[]?tab?=?table; ????int?len?=?tab.length; ????//?expunge?entry?at?staleSlot ????tab[staleSlot].value?=?null; ????tab[staleSlot]?=?null; ????size--; ????//?Rehash?until?we?encounter?null ????Entry?e; ????int?i; ????for?(i?=?nextIndex(staleSlot,?len); ?????????(e?=?tab[i])?!=?null; ?????????i?=?nextIndex(i,?len))?{ ????????ThreadLocal<?>?k?=?e.get(); ????????if?(k?==?null)?{ ????????????e.value?=?null; ????????????tab[i]?=?null; ????????????size--; ????????}?else?{ ????????????int?h?=?k.threadLocalHashCode?&?(len?-?1); ????????????if?(h?!=?i)?{ ????????????????tab[i]?=?null; ????????????????//?Unlike?Knuth?6.4?Algorithm?R,?we?must?scan?until ????????????????//?null?because?multiple?entries?could?have?been?stale. ????????????????while?(tab[h]?!=?null) ????????????????????h?=?nextIndex(h,?len); ????????????????tab[h]?=?e; ????????????} ????????} ????} ????return?i; }
查看全部 -
ThreadLocal源碼之模運算的不同寫法
使用&進位來進行取模運算
/** ?*?Construct?a?new?map?initially?containing?(firstKey,?firstValue). ?*?ThreadLocalMaps?are?constructed?lazily,?so?we?only?create ?*?one?when?we?have?at?least?one?entry?to?put?in?it. ?*/ ThreadLocalMap(ThreadLocal<?>?firstKey,?Object?firstValue)?{ ????table?=?new?Entry[INITIAL_CAPACITY]; ????int?i?=?firstKey.threadLocalHashCode?&?(INITIAL_CAPACITY?-?1); ????table[i]?=?new?Entry(firstKey,?firstValue); ????size?=?1; ????setThreshold(INITIAL_CAPACITY); }
查看全部 -
ThreadLocal源碼之自定義HashMap
初始容量大小16
/** ?*?The?initial?capacity?--?MUST?be?a?power?of?two. ?*/ private?static?final?int?INITIAL_CAPACITY?=?16;
擴容閾值容量空間的2/3
/** ?*?The?next?size?value?at?which?to?resize. ?*/ private?int?threshold;?//?Default?to?0 /** ?*?Set?the?resize?threshold?to?maintain?at?worst?a?2/3?load?factor. ?*/ private?void?setThreshold(int?len)?{ ????threshold?=?len?*?2?/?3; }
解決散列沖突的方式是尋找下一個存儲索引
/** ?*?Set?the?value?associated?with?key. ?* ?*?@param?key?the?thread?local?object ?*?@param?value?the?value?to?be?set ?*/ private?void?set(ThreadLocal<?>?key,?Object?value)?{ ????//?We?don't?use?a?fast?path?as?with?get()?because?it?is?at ????//?least?as?common?to?use?set()?to?create?new?entries?as ????//?it?is?to?replace?existing?ones,?in?which?case,?a?fast ????//?path?would?fail?more?often?than?not. ????Entry[]?tab?=?table; ????int?len?=?tab.length; ????int?i?=?key.threadLocalHashCode?&?(len-1); ????for?(Entry?e?=?tab[i]; ?????????e?!=?null; ?????????e?=?tab[i?=?nextIndex(i,?len)])?{ ????????ThreadLocal<?>?k?=?e.get(); ????????if?(k?==?key)?{ ????????????e.value?=?value; ????????????return; ????????} ????????//?這里做判斷是由于k是WeakReference存儲的,有可能k已經(jīng)被GC回收了 ????????if?(k?==?null)?{ ????????????replaceStaleEntry(key,?value,?i); ????????????return; ????????} ????} ????tab[i]?=?new?Entry(key,?value); ????int?sz?=?++size; ????//?清理k被回收的槽并判斷是否需要擴容 ????if?(!cleanSomeSlots(i,?sz)?&&?sz?>=?threshold) ????????rehash(); }
/** ?*?Increment?i?modulo?len. ?*/ private?static?int?nextIndex(int?i,?int?len)?{ ????return?((i?+?1?<?len)???i?+?1?:?0); }
/** ?*?Replace?a?stale?entry?encountered?during?a?set?operation ?*?with?an?entry?for?the?specified?key.??The?value?passed?in ?*?the?value?parameter?is?stored?in?the?entry,?whether?or?not ?*?an?entry?already?exists?for?the?specified?key. ?* ?*?As?a?side?effect,?this?method?expunges?all?stale?entries?in?the ?*?"run"?containing?the?stale?entry.??(A?run?is?a?sequence?of?entries ?*?between?two?null?slots.) ?* ?*?@param??key?the?key ?*?@param??value?the?value?to?be?associated?with?key ?*?@param??staleSlot?index?of?the?first?stale?entry?encountered?while ?*?????????searching?for?key. ?*/ private?void?replaceStaleEntry(ThreadLocal<?>?key,?Object?value, ???????????????????????????????int?staleSlot)?{ ????Entry[]?tab?=?table; ????int?len?=?tab.length; ????Entry?e; ????//?Back?up?to?check?for?prior?stale?entry?in?current?run. ????//?We?clean?out?whole?runs?at?a?time?to?avoid?continual ????//?incremental?rehashing?due?to?garbage?collector?freeing ????//?up?refs?in?bunches?(i.e.,?whenever?the?collector?runs). ????int?slotToExpunge?=?staleSlot; ????for?(int?i?=?prevIndex(staleSlot,?len); ?????????(e?=?tab[i])?!=?null; ?????????i?=?prevIndex(i,?len)) ????????if?(e.get()?==?null) ????????????slotToExpunge?=?i; ????//?Find?either?the?key?or?trailing?null?slot?of?run,?whichever ????//?occurs?first ????for?(int?i?=?nextIndex(staleSlot,?len); ?????????(e?=?tab[i])?!=?null; ?????????i?=?nextIndex(i,?len))?{ ????????ThreadLocal<?>?k?=?e.get(); ????????//?If?we?find?key,?then?we?need?to?swap?it ????????//?with?the?stale?entry?to?maintain?hash?table?order. ????????//?The?newly?stale?slot,?or?any?other?stale?slot ????????//?encountered?above?it,?can?then?be?sent?to?expungeStaleEntry ????????//?to?remove?or?rehash?all?of?the?other?entries?in?run. ????????if?(k?==?key)?{ ????????????e.value?=?value; ????????????tab[i]?=?tab[staleSlot]; ????????????tab[staleSlot]?=?e; ????????????//?Start?expunge?at?preceding?stale?entry?if?it?exists ????????????if?(slotToExpunge?==?staleSlot) ????????????????slotToExpunge?=?i; ????????????cleanSomeSlots(expungeStaleEntry(slotToExpunge),?len); ????????????return; ????????} ????????//?If?we?didn't?find?stale?entry?on?backward?scan,?the ????????//?first?stale?entry?seen?while?scanning?for?key?is?the ????????//?first?still?present?in?the?run. ????????if?(k?==?null?&&?slotToExpunge?==?staleSlot) ????????????slotToExpunge?=?i; ????} ????//?If?key?not?found,?put?new?entry?in?stale?slot ????tab[staleSlot].value?=?null; ????tab[staleSlot]?=?new?Entry(key,?value); ????//?If?there?are?any?other?stale?entries?in?run,?expunge?them ????if?(slotToExpunge?!=?staleSlot) ????????cleanSomeSlots(expungeStaleEntry(slotToExpunge),?len); }
/** ?*?Heuristically?scan?some?cells?looking?for?stale?entries. ?*?This?is?invoked?when?either?a?new?element?is?added,?or ?*?another?stale?one?has?been?expunged.?It?performs?a ?*?logarithmic?number?of?scans,?as?a?balance?between?no ?*?scanning?(fast?but?retains?garbage)?and?a?number?of?scans ?*?proportional?to?number?of?elements,?that?would?find?all ?*?garbage?but?would?cause?some?insertions?to?take?O(n)?time. ?* ?*?@param?i?a?position?known?NOT?to?hold?a?stale?entry.?The ?*?scan?starts?at?the?element?after?i. ?* ?*?@param?n?scan?control:?{@code?log2(n)}?cells?are?scanned, ?*?unless?a?stale?entry?is?found,?in?which?case ?*?{@code?log2(table.length)-1}?additional?cells?are?scanned. ?*?When?called?from?insertions,?this?parameter?is?the?number ?*?of?elements,?but?when?from?replaceStaleEntry,?it?is?the ?*?table?length.?(Note:?all?this?could?be?changed?to?be?either ?*?more?or?less?aggressive?by?weighting?n?instead?of?just ?*?using?straight?log?n.?But?this?version?is?simple,?fast,?and ?*?seems?to?work?well.) ?* ?*?@return?true?if?any?stale?entries?have?been?removed. ?*/ private?boolean?cleanSomeSlots(int?i,?int?n)?{ ????boolean?removed?=?false; ????Entry[]?tab?=?table; ????int?len?=?tab.length; ????do?{ ????????i?=?nextIndex(i,?len); ????????Entry?e?=?tab[i]; ????????if?(e?!=?null?&&?e.get()?==?null)?{ ????????????n?=?len; ????????????removed?=?true; ????????????i?=?expungeStaleEntry(i); ????????} ????}?while?(?(n?>>>=?1)?!=?0); ????return?removed; }
/** ?*?Re-pack?and/or?re-size?the?table.?First?scan?the?entire ?*?table?removing?stale?entries.?If?this?doesn't?sufficiently ?*?shrink?the?size?of?the?table,?double?the?table?size. ?*/ private?void?rehash()?{ ????expungeStaleEntries(); ????//?Use?lower?threshold?for?doubling?to?avoid?hysteresis ????if?(size?>=?threshold?-?threshold?/?4) ????????resize(); }
resize會擴容為原空間的2倍并重新散列數(shù)據(jù)
/** ?*?Double?the?capacity?of?the?table. ?*/ private?void?resize()?{ ????Entry[]?oldTab?=?table; ????int?oldLen?=?oldTab.length; ????int?newLen?=?oldLen?*?2; ????Entry[]?newTab?=?new?Entry[newLen]; ????int?count?=?0; ????for?(Entry?e?:?oldTab)?{ ????????if?(e?!=?null)?{ ????????????ThreadLocal<?>?k?=?e.get(); ????????????if?(k?==?null)?{ ????????????????e.value?=?null;?//?Help?the?GC ????????????}?else?{ ????????????????int?h?=?k.threadLocalHashCode?&?(newLen?-?1); ????????????????while?(newTab[h]?!=?null) ????????????????????h?=?nextIndex(h,?newLen); ????????????????newTab[h]?=?e; ????????????????count++; ????????????} ????????} ????} ????setThreshold(newLen); ????size?=?count; ????table?=?newTab; }
查看全部 -
ThreadLocal源碼之WeakReference
/** ?*?The?entries?in?this?hash?map?extend?WeakReference,?using ?*?its?main?ref?field?as?the?key?(which?is?always?a ?*?ThreadLocal?object).??Note?that?null?keys?(i.e.?entry.get() ?*?==?null)?mean?that?the?key?is?no?longer?referenced,?so?the ?*?entry?can?be?expunged?from?table.??Such?entries?are?referred?to ?*?as?"stale?entries"?in?the?code?that?follows. ?*/ static?class?Entry?extends?WeakReference<ThreadLocal<?>>?{ ????/**?The?value?associated?with?this?ThreadLocal.?*/ ????Object?value; ????Entry(ThreadLocal<?>?k,?Object?v)?{ ????????super(k); ????????value?=?v; ????} }
ThreadLocalMap.Entry 使用繼承 WeakReference 的方式實現(xiàn)并存儲ThreadLocal實例中的數(shù)據(jù),其目的是為了解決內(nèi)存回收的問題
WeakReference不會計算其存儲對象的引用計數(shù),也就是說當該ThreadLocal實例不再被使用時,在程序執(zhí)行的某一刻Entry中存儲的ThreadLocal<?>引用可能會被GC回收掉
查看全部 -
帶著問題學源碼2
查看全部 -
ThreadLocal源碼之哈希函數(shù)
/** ?*?ThreadLocals?rely?on?per-thread?linear-probe?hash?maps?attached ?*?to?each?thread?(Thread.threadLocals?and ?*?inheritableThreadLocals).??The?ThreadLocal?objects?act?as?keys, ?*?searched?via?threadLocalHashCode.??This?is?a?custom?hash?code ?*?(useful?only?within?ThreadLocalMaps)?that?eliminates?collisions ?*?in?the?common?case?where?consecutively?constructed?ThreadLocals ?*?are?used?by?the?same?threads,?while?remaining?well-behaved?in ?*?less?common?cases. ?*/ private?final?int?threadLocalHashCode?=?nextHashCode(); /** ?*?The?next?hash?code?to?be?given?out.?Updated?atomically.?Starts?at ?*?zero. ?*/ private?static?AtomicInteger?nextHashCode?= ????new?AtomicInteger(); /** ?*?The?difference?between?successively?generated?hash?codes?-?turns ?*?implicit?sequential?thread-local?IDs?into?near-optimally?spread ?*?multiplicative?hash?values?for?power-of-two-sized?tables. ?*/ private?static?final?int?HASH_INCREMENT?=?0x61c88647; /** ?*?Returns?the?next?hash?code. ?*/ private?static?int?nextHashCode()?{ ????return?nextHashCode.getAndAdd(HASH_INCREMENT); }
查看全部 -
ThreadLocal源碼之set方法
/** ?*?Sets?the?current?thread's?copy?of?this?thread-local?variable ?*?to?the?specified?value.??Most?subclasses?will?have?no?need?to ?*?override?this?method,?relying?solely?on?the?{@link?#initialValue} ?*?method?to?set?the?values?of?thread-locals. ?* ?*?@param?value?the?value?to?be?stored?in?the?current?thread's?copy?of ?*????????this?thread-local. ?*/ public?void?set(T?value)?{ ????Thread?t?=?Thread.currentThread(); ????ThreadLocalMap?map?=?getMap(t); ????if?(map?!=?null)?{ ????????map.set(this,?value); ????}?else?{ ????????createMap(t,?value); ????} }
/** ?*?Create?the?map?associated?with?a?ThreadLocal.?Overridden?in ?*?InheritableThreadLocal. ?* ?*?@param?t?the?current?thread ?*?@param?firstValue?value?for?the?initial?entry?of?the?map ?*/ void?createMap(Thread?t,?T?firstValue)?{ ????t.threadLocals?=?new?ThreadLocalMap(this,?firstValue); }
查看全部 -
ThreadLocal源碼之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(); ????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(); }
/** ?*?Get?the?entry?associated?with?key.??This?method ?*?itself?handles?only?the?fast?path:?a?direct?hit?of?existing ?*?key.?It?otherwise?relays?to?getEntryAfterMiss.??This?is ?*?designed?to?maximize?performance?for?direct?hits,?in?part ?*?by?making?this?method?readily?inlinable. ?* ?*?@param??key?the?thread?local?object ?*?@return?the?entry?associated?with?key,?or?null?if?no?such ?*/ private?Entry?getEntry(ThreadLocal<?>?key)?{ ????int?i?=?key.threadLocalHashCode?&?(table.length?-?1); ????Entry?e?=?table[i]; ????if?(e?!=?null?&&?e.get()?==?key) ????????return?e; ????else ????????return?getEntryAfterMiss(key,?i,?e); }
/** ?*?Variant?of?set()?to?establish?initialValue.?Used?instead ?*?of?set()?in?case?user?has?overridden?the?set()?method. ?* ?*?@return?the?initial?value ?*/ private?T?setInitialValue()?{ ????T?value?=?initialValue(); ????Thread?t?=?Thread.currentThread(); ????ThreadLocalMap?map?=?getMap(t); ????if?(map?!=?null)?{ ????????map.set(this,?value); ????}?else?{ ????????createMap(t,?value); ????} ????if?(this?instanceof?TerminatingThreadLocal)?{ ????????TerminatingThreadLocal.register((TerminatingThreadLocal<?>)?this); ????} ????return?value; }
查看全部 -
帶著問題學習源碼
查看全部 -
為什么ThreadLocal源碼中的getMap方法沒有使用Synchronize關鍵字修飾?
MyThreadLocal中使用Synchronize方法是為了獲取threadLocalMap臨界區(qū),保證其是線程安全的。而在Thread源碼中維護了ThreadLocal.ThreadLocalMap,因此無需在ThreadLocal中維護ThreadLocalMap
Thread 源碼
/*?ThreadLocal?values?pertaining?to?this?thread.?This?map?is?maintained ?*?by?the?ThreadLocal?class.?*/ ThreadLocal.ThreadLocalMap?threadLocals?=?null;
ThreadLocal源碼
/** ?*?Get?the?map?associated?with?a?ThreadLocal.?Overridden?in ?*?InheritableThreadLocal. ?* ?*?@param??t?the?current?thread ?*?@return?the?map ?*/ ThreadLocalMap?getMap(Thread?t)?{ ????return?t.threadLocals; }
查看全部 -
可以引入鏈表解決哈希沖突,如果槽很大,則Map占用的內(nèi)存就越大,因此槽不是越大越好
能將數(shù)據(jù)散列的更分散的哈希函數(shù)更好
數(shù)據(jù)散列集中的危害是查詢數(shù)據(jù)時的時間復雜度比較高?
查看全部 -
解決hash沖突
查看全部 -
thread local 源碼分析之 spring
查看全部 -
thread local 源碼分析之 mybatis
查看全部 -
thread local 源碼分析之 quartz
查看全部
舉報