ThreadLocal鏄疛DK1.2鎻愪緵鐨勪竴涓伐鍏枫€備綔鑰呬箣涓€涔熸槸鐭ュ悕鑰佹澘DougLea銆傝繖涓伐鍏蜂富瑕佹槸瑙e喅澶氱嚎绋嬩笅鍏变韩璧勬簮鐨勯棶棰樸€傛帴涓嬫潵锛屾垜浠粠ThreadLocal鐨勫畾涔夊拰閫傜敤鍦烘櫙寮€濮嬶紝涓€姝ユ鑴辨帀瀹冪殑澶栬。閫傜敤鍦烘櫙鍦烘櫙1锛孴hreadLocal鐢ㄤ簬淇濆瓨姣忎釜绾跨▼鐨勭嫭鍗犲璞★紝骞朵负姣忎釜绾跨▼鍒涘缓涓€涓壇鏈紝璁╂瘡涓嚎绋嬮兘鍙互淇敼鑷繁鎷ユ湁鐨勫壇鏈笉浼氬奖鍝嶅叾浠栫嚎绋嬬殑鍓湰锛屼繚璇佺嚎绋嬪畨鍏ㄣ€傚満鏅簩锛孴hreadLocal鐢ㄤ綔闇€瑕佸湪姣忎釜绾跨▼涓嫭绔嬩繚瀛樹俊鎭殑鍦烘櫙锛屼互渚垮叾浠栨柟娉曟洿鏂逛究鐨勮幏鍙栦俊鎭€傛瘡涓嚎绋嬭幏鍙栫殑淇℃伅鍙兘涓嶅悓銆傚墠闈㈡墽琛岀殑鏂规硶淇濆瓨淇℃伅鍚庯紝鍚庨潰鐨勬柟娉曞彲浠ョ洿鎺ラ€氳繃ThreadLocal鑾峰彇锛岄伩鍏嶄簡鍙傛暟浼犻€掞紝绫讳技浜庡叏灞€鍙橀噺鐨勬蹇点€傚満鏅竴鎴戜滑鍘婚キ搴楃偣浜嗕竴妗岃彍锛屾湁闈㈡潯銆佺倰鑿溿€佺孩鐑ц彍銆傝繖瀹堕鍘呯殑鍘ㄥ笀闈炲父鐑儏銆傛瘡涓帹甯堥兘鎯充负鎮ㄦ湇鍔°€傜涓€浣嶅帹甯堝湪闈㈡潯涓婃斁浜嗕竴鎶婄洂銆備簩鍘ㄤ笉鐭ラ亾锛屼粬杩樺湪闈㈡潯涓婃斁浜嗙洂銆傛垜鐭ラ亾鎴戜篃缁欒繖涓潰鎾掍簡鐩愶紝鍥涘帹.......杩欏氨鍍忓绾跨▼锛岀嚎绋嬫槸涓嶅畨鍏ㄧ殑锛屾墍浠ougLea璇达紝浣犱滑涓€涓汉璐熻矗鍋氫竴閬撹彍锛宒on涔辨潵銆傝鎴戜滑涓婁笅浠g爜鏉ユ紨绀鸿繖涓畝鍗曠殑渚嬪瓙锛?00涓嚎绋嬪繀椤讳娇鐢⊿impleDateFormat锛塸ublicstaticExecutorServicethreadPool=Executors.newFixedThreadPool(16);staticSimpleDateFormatdateFormat=newSimpleDateFormat("mm:ss");publicstaticvoidmain(String[]args)throwsInterruptedException{for(inti=0;i<100;i++){intfinalI=i;threadPool.submit(newRunnable(){@Overridepublicvoidrun(){Stringdate=newThreadLocalDemo01().date(finalI);System.out.println(date);}});}threadPool.shutdown();}publicStringdate(intseconds){Datedate=newDate(1000*seconds);returndateFormat.format(date);}Output:00:0500:0700:0500:0500:0600:0500:0500:1100:0500:1200:10鎵ц涓婇潰鐨勪唬鐮侊紝浣犱細鍙戠幇鎺у埗鍙版墦鍗扮殑鏄拰鎴戜滑鏈熸湜鐨勪笉涓€鑷寸殑鏄紝鎴戜滑鏈熸湜鐨勬槸鎵撳嵃鍑烘潵鐨勬椂闂存病鏈夐噸澶嶏紝浣嗘槸杩欓噷鍙互鐪嬪嚭鏈夐噸澶嶏紝姣斿绗竴琛屽拰绗笁琛岄兘鏄?5绉掞紝璇存槑瀹冨彂鐢熶簡鍐呴儴閿欒杩欐椂鍊欒仾鏄庣殑鍚屽鏄笉鏄鍔犻攣灏卞彲浠ヨВ鍐冲苟鍙戦棶棰樺憿锛熼偅鏄竴涓ソ涓绘剰銆傛妸浠g爜鏀规垚杩欎釜publicstaticExecutorServicethreadPool=Executors.newFixedThreadPool(16);staticSimpleDateFormatdateFormat=newSimpleDateFormat("mm:ss");publicstaticvoidmain(String[]args)throwsInterruptedException{for(inti=0;i<1000;i++){intfinalI=i;threadPool.submit(newRunnable(){@Overridepublicvoidrun(){Stringdate=newThreadLocalDemo05().date(finalI);System.out.println(date);}});}threadPool.shutdown();}publicStringdate(intseconds){Datedate=newDate(1000*seconds);瀛楃涓瞫=null锛涘悓姝?ThreadLocalDemo05.class){s=dateFormat.format(date);}杩斿洖s;瀹冨凡缁忓ぇ澶у噺灏戜簡銆傞偅涔堟湁娌℃湁鍚冭タ鐡滄崱鑺濋夯鐨勬柟娉曞憿锛熸瘡涓嚎绋嬮兘鍙互鏈夎嚜宸辩殑simpleDateFormat瀵硅薄鏉ヨ揪鍒拌繖涓洰鏍囩殑锛岃繖鏍峰氨鑳戒袱鍏ㄥ叾缇庝簡锛岃骞插氨骞瞤ublicclassThreadLocalDemo06{publicstaticExecutorServicethreadPool=Executors.newFixedThreadPool(16);publicstaticvoidmain(String[]args)throwsInterruptedException{for(inti=0;i<1000;i++){intfinalI=i;threadPool.submit(newRunnable(){@Overridepublicvoidrun(){Stringdate=newThreadLocalDemo06().date(finalI);System.out.println(date);}});}threadPool.shutdown();}publicStringdate(intseconds){Datedate=newDate(1000*seconds);SimpleDateFormatdateFormat=ThreadSafeFormatter.dateFormatThreadLocal.get();杩斿洖dateFormat.format(鏃ユ湡);}}classThreadSafeFormatter{publicstaticThreadLocaldateFormatThreadLocal=newThreadLocal(){@OverrideprotectedSimpleDateFormatinitialValue(){returnnewSimpleDateFormat("mm:ss");}};}鍦烘櫙2ok鍦烘櫙2鏄垜浠湪褰撳墠椤圭洰涓娇鐢ㄧ殑鍦烘櫙銆傛垜浠娇鐢═hreadLocal鏉ユ帶鍒舵暟鎹潈闄愩€傛垜浠鍋氱殑鏄湪姣忎釜绾跨▼涓兘闇€瑕佷繚瀛樻瘡涓€涓被浼间簬鍏ㄥ眬鍙橀噺鐨勪俊鎭紙姣斿鍦ㄦ嫤鎴櫒涓幏鍙栧埌鐨勭敤鎴蜂俊鎭級锛屼笉鍚岀殑鏂规硶鍙互鐩存帴浣跨敤锛岄伩鍏嶄簡浼犲弬鍙堜笉鎯崇殑楹荤儲琚涓嚎绋嬪叡浜紙鍥犱负涓嶅悓绾跨▼鑾峰彇鐨勭敤鎴蜂俊鎭笉涓€鏍凤級姣斿浣跨敤ThreadLocal淇濆瓨涓€浜涗笟鍔″唴瀹癸紝姣斿涓€涓猆serRequest锛岄噷闈繚瀛樹簡涓€浜涚敤鎴蜂俊鎭紝姣斿绾跨▼鐢熷懡鍛ㄦ湡涓殑鏉冮檺缁勶紝缂栧彿绛変俊鎭紝閫氳繃杩欎釜闈欐€乀hreadLocal瀹炰緥鐨刧et()鏂规硶鑾峰彇鑷繁璁剧疆浼犻€掔殑瀵硅薄锛岄伩鍏嶄簡灏嗚繖涓姹備綔涓哄弬鏁颁紶閫掔殑楹荤儲锛屾墍浠ユ垜浠啓浜嗚繖鏍蜂竴涓伐鍏风被publicclassAppUserContextUtil{privatestaticThreadLocaluserRequest=newThreadLocal();/***鑾峰彇鐢ㄦ埛璇锋眰**@return*/publicstaticStringgetUserRequest(){returnuserRequest.get();}/***璁剧疆鐢ㄦ埛璇锋眰**@paramparam*/publicstaticvoidsetUserRequest(Stringparam){userRequest.set(param);}/***鍒犻櫎userRequest*/publicstaticvoidremoveUserRequest(){userRequest.remove();}}閭d箞褰撲竴涓姹傝繘鏉ョ殑鏃跺€欙紝灏变細鏈変竴涓嚎绋嬭礋璐f墽琛岃繖涓姹傦紝涓嶇杩欎釜璇锋眰缁忚繃浜嗗灏戜釜绫荤殑method锛岄兘鍙互鐩存帴鎷垮埌鎴戜滑鐨剈serRequest鏉ヨ繘琛屼笟鍔″鐞嗘垨鑰呮潈闄愭帶鍒躲€俆hread涓浣曞瓨鍌紝浜岃瘽涓嶈锛屼笂鍥句腑涓€涓猅hread涓彧鏈変竴涓猅hreadLocalMap锛屼絾鏄竴涓猅hreadLocalMap涓彲浠ユ湁澶氫釜ThreadLocal锛屾瘡涓猅hreadLocal瀵瑰簲涓€涓獀alue銆傚洜涓轰竴涓猅hread鍙互璋冪敤澶氫釜ThreadLocal锛孴hread浣跨敤ThreadLocalMap绛塎ap鏁版嵁缁撴瀯鏉ュ瓨鍌═hreadLocal鍜寁alue銆傛垜浠湅涓€涓嬪唴閮ㄧ被ThreadLocalMapstaticclassThreadLocalMap{staticclassEntryextendsWeakReference>{/**杩欎釜ThreadLocal鍏宠仈鐨勫€笺€?/瀵硅薄鍊硷紱鏉$洰锛圱hreadLocal<锛?k锛屽璞锛墈瓒呯骇锛坘锛?鍊?v锛泒}privateEntry[]table;//...}ThreadLocalMap绫绘槸姣忎釜绾跨▼鐨凾hread绫讳腑鐨勪竴涓垚鍛樺彉閲忥紝鍏朵腑鏈€閲嶈鐨勬槸鎷︽埅浠g爜鐨凟ntry鍐呴儴绫汇€俆hreadLocalMap涓細鏈変竴涓狤ntry绫诲瀷鐨勬暟缁勶紝鍛藉悕涓簍able銆傛垜浠彲浠ユ妸Entry鐞嗚В鎴愪竴涓猰ap锛屽畠鐨勯敭鍊煎鏄細key锛屽綋鍓嶇殑ThreadLocal锛泇alue锛屽疄闄呴渶瑕佸瓨鍌ㄧ殑鍙橀噺锛屾瘮濡倁ser鐢ㄦ埛瀵硅薄鎴栬€卻impleDateFormat瀵硅薄绛夈€傜敱浜嶵hreadLocalMap绫讳技浜嶮ap锛屽畠涔熸湁set銆乬et銆乺ehash銆乺esize绛変竴绯诲垪鏍囧噯鎿嶄綔锛屽氨鍍廐ashMap涓€鏍?涓嶈繃铏界劧鎬濊矾鍜孒ashMap绫讳技锛屼絾鏄叿浣撳疄鐜颁笂杩樻槸浼氭湁浜涗笉鍚屻€備緥濡傦紝鍏朵腑涓€涓尯鍒槸鎴戜滑鐭ラ亾HashMap鍦ㄩ潰涓村搱甯屽啿绐佹椂浣跨敤鐨勬槸鎷夐摼鏂瑰紡銆備絾鏄紝ThreadLocalMap瑙e喅鍝堝笇鍐茬獊鐨勬柟寮忔槸涓嶅悓鐨勩€傚畠閲囩敤绾挎€ф娴嬫柟娉曘€傚鏋滄湁鍐茬獊锛屽垯涓嶄細浠ラ摼琛ㄧ殑褰㈠紡寰€涓嬮摼锛岃€屾槸缁х画瀵绘壘涓嬩竴涓┖鏍煎瓙銆傝繖灏辨槸ThreadLocalMap鍜孒ashMap鍦ㄥ鐞嗗啿绐佹椂鐨勫尯鍒€備娇鐢ㄥЭ鍔縆ey娉勬紡銆傚垰鎵嶆垜浠粙缁嶄簡ThreadLocalMap锛屾瘡涓猅hreadLocal閮芥湁涓€涓猅hreadLocalMap銆傝櫧鐒舵垜浠彲鑳戒細杩欐牱鎿嶄綔ThreadLocalinstance=null锛屼絾鏄妸杩欎釜瀹炰緥缃负null锛岃繖鏍锋兂灏卞彲浠ラ珮鏋曟棤蹇т簡銆備絾鏄粡杩嘒C涓ユ牸鐨勫彲杈炬€у垎鏋愶紝铏界劧鎴戜滑鍦ㄤ笟鍔′唬鐮佷腑灏員hreadLocal瀹炰緥璁剧疆涓簄ull锛屼絾鏄湪Thread绫讳腑浠嶇劧瀛樺湪杩欐潯寮曠敤閾俱€侴C鍦ㄥ瀮鍦惧洖鏀剁殑鏃跺€欎細杩涜鍙揪鎬у垎鏋愶紝浼氬彂鐜癟hreadLocal瀵硅薄浠嶇劧鏄彲杈剧殑锛屾墍浠ヤ笉浼氬杩欎釜ThreadLocal瀵硅薄杩涜鍨冨溇鍥炴敹锛屼粠鑰岄€犳垚鍐呭瓨娉勬紡銆傝繖瀵艰嚧OOM锛岃繘鑰屽鑷村崐澶滄姤璀︼紝杩涜€屽鑷存€ц兘325锛岃繘鑰屽鑷磋緸鑱屻€侀€佸鍗栫瓑涓€绯诲垪鍙嶅簲銆侱ougLea鑰冭檻鍒拌繖鏍风殑鍗遍櫓锛屾墍浠hreadLocalMap涓殑Entry缁ф壙浜哤eakReference鐨勫急寮曠敤锛岄潤鎬佺被EntryextendsWeakReference>{/**涓庢ThreadLocal鍏宠仈鐨勫€笺€?/瀵硅薄鍊硷紱鏉$洰锛圱hreadLocal<锛?k锛屽璞锛墈瓒呯骇锛坘锛?鍊?v锛泒}濡傛偍鎵€瑙侊紝杩欎釜Entry鏄痚xtendsWeakReference銆傚急寮曠敤鐨勭壒鐐规槸锛屽鏋滃璞″彧鍏宠仈浜嗗急寮曠敤锛屾病鏈夊叧鑱斾换浣曞己寮曠敤锛岄偅涔堣繖涓璞℃槸鍙互琚洖鏀剁殑锛屾墍浠ュ急寮曠敤涓嶄細闃绘GC銆傚洜姝わ紝杩欑寮卞紩鐢ㄦ満鍒堕伩鍏嶄簡ThreadLocal鐨勫唴瀛樻硠婕忛棶棰樸€俈alueleakage鎴戜滑浠旂粏鎯虫兂锛孴hreadLocalMap鐨勬瘡涓€涓狤ntry閮芥槸瀵筴ey鐨勫急寮曠敤锛屼絾鏄繖涓狤ntry涓寘鍚簡瀵箆alue鐨勫己寮曠敤锛屼篃灏辨槸璇村湪绾跨▼鐨勭敓鍛芥病鏈夌粨鏉熺殑鏃跺€欙紝鎴戜滑鐨勫彉閲忎細涓€鐩村瓨鍦ㄣ€傚畠鍦ㄦ垜浠殑璁板繂涓紝浣嗗緢鍙兘鎴戜滑寰堥暱涓€娈垫椂闂撮兘涓嶉渶瑕佽繖涓彉閲忋€侱ougLea鏄釜鏆栫敺銆備粬宸茬粡涓烘垜浠€冭檻杩囪繖涓棶棰樸€俆hreadLocal鍦ㄦ墽琛宻et銆乺emove銆乺ehash绛夋柟娉曟椂锛屼細鎵弿key鏄惁涓簄ullEntry锛屽鏋滃彂鐜版煇涓狤ntry鐨刱ey涓簄ull锛屽垯璇存槑鍏跺搴旂殑value鏃犵敤锛屽洜姝や細灏嗗搴旂殑value璁剧疆涓簄ull锛岃繖鏍峰€煎璞″氨鍙互姝e父鍥炴敹浜嗐€備絾鏄亣璁句笉鍐嶄娇鐢═hreadLocal锛岄偅涔坰et銆乺emove銆乺ehash鏂规硶瀹為檯涓婃槸涓嶄細琚皟鐢ㄧ殑銆傚悓鏃讹紝濡傛灉绾跨▼杩樻椿鐫€锛屾病鏈夌粓姝紝閭d箞杩欏潡鍐呭瓨姘歌繙涓嶄細琚獹C锛屼篃姘歌繙涓嶄細琚皟鐢ㄣ€傚鑷磛alue鐨勫唴瀛樻硠婕忥紝杩涜€屽鑷碠OM锛岃繘鑰屽鑷村崐澶滄姤璀︼紝杩涜€屽鑷存€ц兘325锛岃繘鑰屽鑷磋緸鑱屻€侀€佸鍗栫瓑涓€绯诲垪鍙嶅簲銆備负浜嗛伩鍏嶆偛鍓у彂鐢燂紝鎴戜滑搴旇鍦ㄤ娇鐢ㄥ畬ThreadLocal涔嬪悗鎵嬪姩璋冪敤remove鏂规硶锛岀洰鐨勬槸闃叉鍐呭瓨娉勬紡鐨勫彂鐢熴€俻ublicvoidremove(){ThreadLocalMapm=getMap(Thread.currentThread());if(m!=null)m.remove(this);}remove鏂规硶锛屽彲浠ョ湅鍑哄畠棣栧厛鑾峰彇浜員hreadLocalMap鐨勫紩鐢紝璋冪敤浜嗗畠鐨剅emove鏂规硶銆傝繖閲岀殑remove鏂规硶鍙互鎶妅ey瀵瑰簲鐨剉alue娓呯悊鎺夛紝杩欐牱value灏卞彲浠ヨGC鍥炴敹浜嗐€傛€荤粨浠ヤ笂灏辨槸銆婃祬璋?ThreadLocal 鐨勫疄闄呰繍鐢?銆嬬殑鍏ㄩ儴鍐呭銆傜幇鍦鸿繘琛屼簡浠g爜婕旂ず锛涙垜浜嗚В浜員hreadLocal鏄浣曞瓨鍌ㄥ湪绾跨▼涓殑锛涗篃瀛︿細浜嗕娇鐢═hreadLocal鐨勬纭Э鍔裤€傚鏋滄湰鏂囧鎮ㄦ湁甯姪锛岃鐐硅禐鍏虫敞銆傪煓?/p>