---
title: åæJavaå¹¶åé¢è¯å®ä¹ThreadLocal
category:
- Javaæ ¸å¿
- å¹¶åç¼ç¨
tag:
- Java
---
## ThreadLocalçç®ä»
å¨å¤çº¿ç¨ç¼ç¨ä¸é常解å³çº¿ç¨å®å
¨çé®é¢æä»¬ä¼å©ç¨synchronzedæè
lockæ§å¶çº¿ç¨å¯¹ä¸´çåºèµæºçåæ¥é¡ºåºä»èè§£å³çº¿ç¨å®å
¨çé®é¢ï¼ä½æ¯è¿ç§å éçæ¹å¼ä¼è®©æªè·åå°éç线ç¨è¿è¡é»å¡çå¾
ï¼å¾æ¾ç¶è¿ç§æ¹å¼çæ¶é´æç并䏿¯å¾å¥½ã
**线ç¨å®å
¨é®é¢çæ ¸å¿å¨äºå¤ä¸ªçº¿ç¨ä¼å¯¹åä¸ä¸ªä¸´çåºå
±äº«èµæºè¿è¡æä½**ï¼é£ä¹ï¼å¦ææ¯ä¸ªçº¿ç¨é½ä½¿ç¨èªå·±çâå
±äº«èµæºâï¼åèªä½¿ç¨åèªçï¼åäºç¸ä¸å½±åå°å½¼æ¤å³è®©å¤ä¸ªçº¿ç¨é´è¾¾å°é离çç¶æï¼è¿æ ·å°±ä¸ä¼åºç°çº¿ç¨å®å
¨çé®é¢ã
äºå®ä¸ï¼è¿å°±æ¯ä¸ç§â**ç©ºé´æ¢æ¶é´**âçæ¹æ¡ï¼æ¯ä¸ªçº¿ç¨é½ä¼é½æ¥æèªå·±çâå
±äº«èµæºâæ çå
åä¼å¤§å¾å¤ï¼ä½æ¯ç±äºä¸éè¦åæ¥ä¹å°±åå°äºçº¿ç¨å¯è½åå¨çé»å¡çå¾
çæ
åµä»èæé«çæ¶é´æçã
è½ç¶ThreadLocalå¹¶ä¸å¨java.util.concurrentå
ä¸èå¨java.langå
ä¸ï¼ä½ææ´å¾åäºæå®å½ä½æ¯ä¸ç§å¹¶å容å¨ï¼è½ç¶çæ£åæ¾æ°æ®çæ¯ThreadLoclMapï¼è¿è¡å½ç±»ã
ä»**ThreadLocalè¿ä¸ªç±»åå¯ä»¥é¡¾åæä¹çè¿è¡çè§£ï¼è¡¨ç¤ºçº¿ç¨çâæ¬å°åéâï¼å³æ¯ä¸ªçº¿ç¨é½æ¥æè¯¥åé坿¬ï¼è¾¾å°äººæä¸ä»½çææï¼åç¨åçè¿æ ·å°±å¯ä»¥é¿å
å
±äº«èµæºçç«äº**ã
## ThreadLocalçå®ç°åç
è¦æ³å¦ä¹ å°ThreadLocalçå®ç°åçï¼å°±å¿
é¡»äºè§£å®çå ä¸ªæ ¸å¿æ¹æ³ï¼å
æ¬ææ ·åææ ·åççï¼ä¸é¢æä»¬ä¸ä¸ªä¸ªæ¥çã
### `void set(T value)`
**setæ¹æ³è®¾ç½®å¨å½å线ç¨ä¸threadLocalåéçå¼**ï¼è¯¥æ¹æ³çæºç 为ï¼
```java
public void set(T value) {
//1. è·åå½å线ç¨å®ä¾å¯¹è±¡
Thread t = Thread.currentThread();
//2. éè¿å½å线ç¨å®ä¾è·åå°ThreadLocalMap对象
ThreadLocalMap map = getMap(t);
if (map != null)
//3. 妿Mapä¸ä¸ºnull,å以å½åthreadLoclå®ä¾ä¸ºkey,å¼ä¸ºvalueè¿è¡åå
¥
map.set(this, value);
else
//4.map为null,åæ°å»ºThreadLocalMapå¹¶åå
¥value
createMap(t, value);
}
```
æ¹æ³çé»è¾å¾æ¸
æ°ï¼å
·ä½è¯·çä¸é¢ç注éãéè¿æºç æä»¬ç¥évalueæ¯åæ¾å¨äºThreadLocalMapéäºï¼å½åå
æå®ç解为ä¸ä¸ªæ®æ®ééçmapå³å¯ï¼ä¹å°±æ¯è¯´ï¼**æ°æ®valueæ¯çæ£çåæ¾å¨äºThreadLocalMapè¿ä¸ªå®¹å¨ä¸äºï¼å¹¶ä¸æ¯ä»¥å½åthreadLocalå®ä¾ä¸ºkey**ãå
ç®åççä¸ThreadLocalMapæ¯ä»ä¹ï¼æä¸ªç®åç认è¯å°±å¥½ï¼ä¸é¢ä¼å
·ä½è¯´çã
**é¦å
ThreadLocalMapæ¯ææ ·æ¥ç**ï¼æºç 徿¸
æ¥ï¼æ¯éè¿`getMap(t)`è¿è¡è·åï¼
```java
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
```
è¯¥æ¹æ³ç´æ¥è¿åçå°±æ¯å½å线ç¨å¯¹è±¡tçä¸ä¸ªæååéthreadLocalsï¼
```java
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
```
ä¹å°±æ¯è¯´**ThreadLocalMapçå¼ç¨æ¯ä½ä¸ºThreadçä¸ä¸ªæååéï¼è¢«Threadè¿è¡ç»´æ¤ç**ãåè¿å¤´åæ¥ççsetæ¹æ³ï¼å½map为Nullçæ¶åä¼éè¿`createMap(tï¼value)`æ¹æ³ï¼
```java
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
```
è¯¥æ¹æ³å°±æ¯**newä¸ä¸ªThreadLocalMapå®ä¾å¯¹è±¡ï¼ç¶ååæ ·ä»¥å½åthreadLocalå®ä¾ä½ä¸ºkey,å¼ä¸ºvalueåæ¾å°threadLocalMapä¸ï¼ç¶åå°å½å线ç¨å¯¹è±¡çthreadLocalsèµå¼ä¸ºthreadLocalMap**ã
ç°å¨æ¥å¯¹setæ¹æ³è¿è¡æ»ç»ä¸ä¸ï¼
**éè¿å½å线ç¨å¯¹è±¡threadè·å该threadæç»´æ¤çthreadLocalMap,è¥threadLocalMapä¸ä¸ºnull,å以threadLocalå®ä¾ä¸ºkey,å¼ä¸ºvalueçé®å¼å¯¹åå
¥threadLocalMap,è¥threadLocalMap为nullçè¯ï¼å°±æ°å»ºthreadLocalMapç¶åå¨ä»¥threadLocal为é®ï¼å¼ä¸ºvalueçé®å¼å¯¹åå
¥å³å¯**ã
```java
T get()
```
**getæ¹æ³æ¯è·åå½å线ç¨ä¸threadLocalåéçå¼**ï¼åæ ·çè¿æ¯æ¥ççæºç ï¼
```java
public T get() {
//1. è·åå½å线ç¨çå®ä¾å¯¹è±¡
Thread t = Thread.currentThread();
//2. è·åå½å线ç¨çthreadLocalMap
ThreadLocalMap map = getMap(t);
if (map != null) {
//3. è·åmapä¸å½åthreadLocalå®ä¾ä¸ºkeyçå¼çentry
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
//4. å½åentitiyä¸ä¸ºnullçè¯ï¼å°±è¿åç¸åºçå¼value
T result = (T)e.value;
return result;
}
}
//5. è¥map为nullæè
entry为nullçè¯éè¿è¯¥æ¹æ³åå§åï¼å¹¶è¿åè¯¥æ¹æ³è¿åçvalue
return setInitialValue();
}
```
弿äºsetæ¹æ³çé»è¾ï¼çgetæ¹æ³åªéè¦å¸¦çéåæç»´å»ç就好ï¼å¦ææ¯é£æ ·åçï¼åè¿æ¥å»æ¿å°±å¥½ã代ç é»è¾è¯·ç注éï¼å¦å¤ï¼çä¸setInitialValue主è¦åäºäºä»ä¹äºæ
ï¼
```java
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);
return value;
}
```
è¿æ®µæ¹æ³çé»è¾åsetæ¹æ³å ä¹ä¸è´ï¼å¦å¤å¼å¾å
³æ³¨çæ¯initialValueæ¹æ³:
```java
protected T initialValue() {
return null;
}
```
è¿ä¸ª**æ¹æ³æ¯protected修饰çä¹å°±æ¯è¯´ç»§æ¿ThreadLocalçåç±»å¯éåè¯¥æ¹æ³ï¼å®ç°èµå¼ä¸ºå
¶ä»çåå§å¼**ãå
³äºgetæ¹æ³æ¥æ»ç»ä¸ä¸ï¼
**éè¿å½å线ç¨threadå®ä¾è·åå°å®æç»´æ¤çthreadLocalMapï¼ç¶å以å½åthreadLocalå®ä¾ä¸ºkeyè·å该mapä¸çé®å¼å¯¹ï¼Entryï¼ï¼è¥Entryä¸ä¸ºnullåè¿åEntryçvalueã妿è·åthreadLocalMap为nullæè
Entry为nullçè¯ï¼å°±ä»¥å½åthreadLocal为Keyï¼value为nullåå
¥mapåï¼å¹¶è¿ånullã**
### `void remove()`
```java
public void remove() {
//1. è·åå½å线ç¨çthreadLocalMap
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
//2. ä»mapä¸å é¤ä»¥å½åthreadLocalå®ä¾ä¸ºkeyçé®å¼å¯¹
m.remove(this);
}
```
get,setæ¹æ³å®ç°äºåæ°æ®åè¯»æ°æ®ï¼æä»¬å½ç¶è¿å¾å¦ä¼å¦ä½å æ°æ®**ãå 餿°æ®å½ç¶æ¯ä»mapä¸å 餿°æ®ï¼å
è·åä¸å½å线ç¨ç¸å
³èçthreadLocalMapç¶åä»mapä¸å é¤è¯¥threadLocalå®ä¾ä¸ºkeyçé®å¼å¯¹å³å¯**ã
## ThreadLocalMap详解
ä»ä¸é¢ç忿们已ç»ç¥éï¼æ°æ®å
¶å®é½æ¾å¨äºthreadLocalMapä¸ï¼threadLocalçgetï¼setåremoveæ¹æ³å®é
ä¸å
·ä½æ¯éè¿threadLocalMapçgetEntry,setåremoveæ¹æ³å®ç°çã妿æ³çæ£å
¨æ¹ä½ç弿threadLocalï¼å¿å¿
å¾å¨å¯¹threadLocalMapåä¸çªçè§£ã
### Entryæ°æ®ç»æ
ThreadLocalMapæ¯threadLocalä¸ä¸ªéæå
é¨ç±»ï¼å大夿°å®¹å¨ä¸æ ·å
é¨ç»´æ¤äºä¸ä¸ªæ°ç»ï¼åæ ·çthreadLocalMapå
é¨ç»´æ¤äºä¸ä¸ªEntryç±»åçtableæ°ç»ã
```java
/**
* The table, resized as necessary.
* table.length MUST always be a power of two.
*/
private Entry[] table;
```
éè¿æ³¨éå¯ä»¥çåºï¼tableæ°ç»çé¿åº¦ä¸º2ç广¬¡æ¹ãæ¥ä¸æ¥çä¸Entryæ¯ä»ä¹ï¼
```java
static class Entry extends WeakReference> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal> k, Object v) {
super(k);
value = v;
}
}
```
Entryæ¯ä¸ä¸ªä»¥ThreadLocal为key,Object为valueçé®å¼å¯¹ï¼å¦å¤éè¦æ³¨æçæ¯è¿éç**threadLocalæ¯å¼±å¼ç¨ï¼å 为Entryç»§æ¿äºWeakReferenceï¼å¨Entryçæé æ¹æ³ä¸ï¼è°ç¨äºsuper(k)æ¹æ³å°±ä¼å°threadLocalå®ä¾å
è£
æä¸ä¸ªWeakRefereneceã**
å°è¿éæä»¬å¯ä»¥ç¨ä¸ä¸ªå¾æ¥çè§£ä¸thread,threadLocal,threadLocalMapï¼Entryä¹é´çå
³ç³»ï¼

注æä¸å¾ä¸çå®çº¿è¡¨ç¤ºå¼ºå¼ç¨ï¼è线表示弱å¼ç¨ãå¦å¾æç¤ºï¼æ¯ä¸ªçº¿ç¨å®ä¾ä¸å¯ä»¥éè¿threadLocalsè·åå°threadLocalMapï¼èthreadLocalMapå®é
ä¸å°±æ¯ä¸ä¸ªä»¥threadLocalå®ä¾ä¸ºkeyï¼ä»»æå¯¹è±¡ä¸ºvalueçEntryæ°ç»ã
å½æä»¬ä¸ºthreadLocalåéèµå¼ï¼å®é
ä¸å°±æ¯ä»¥å½åthreadLocalå®ä¾ä¸ºkeyï¼å¼ä¸ºvalueçEntryå¾è¿ä¸ªthreadLocalMapä¸åæ¾ã
éè¦æ³¨æçæ¯**Entryä¸çkeyæ¯å¼±å¼ç¨ï¼å½threadLocalå¤é¨å¼ºå¼ç¨è¢«ç½®ä¸ºnull(`threadLocalInstance=null`),é£ä¹ç³»ç» GC çæ¶åï¼æ ¹æ®å¯è¾¾æ§åæï¼è¿ä¸ªthreadLocalå®ä¾å°±æ²¡æä»»ä½ä¸æ¡é¾è·¯è½å¤å¼ç¨å°å®ï¼è¿ä¸ªThreadLocalå¿å¿
ä¼è¢«åæ¶ï¼è¿æ ·ä¸æ¥ï¼ThreadLocalMapä¸å°±ä¼åºç°key为nullçEntryï¼å°±æ²¡æåæ³è®¿é®è¿äºkey为nullçEntryçvalueï¼å¦æå½å线ç¨åè¿è¿ä¸ç»æçè¯ï¼è¿äºkey为nullçEntryçvalueå°±ä¼ä¸ç´åå¨ä¸æ¡å¼ºå¼ç¨é¾ï¼Thread Ref -> Thread -> ThreaLocalMap -> Entry -> valueæ°¸è¿æ æ³åæ¶ï¼é æå
åæ³æ¼**ã
å½ç¶ï¼å¦æå½åthreadè¿è¡ç»æï¼threadLocalï¼threadLocalMap,Entry没æå¼ç¨é¾å¯è¾¾ï¼å¨åå¾åæ¶çæ¶åé½ä¼è¢«ç³»ç»è¿è¡åæ¶ãå¨å®é
å¼åä¸ï¼ä¼ä½¿ç¨çº¿ç¨æ± å»ç»´æ¤çº¿ç¨çå建åå¤ç¨ï¼æ¯å¦åºå®å¤§å°ççº¿ç¨æ± ï¼çº¿ç¨ä¸ºäºå¤ç¨æ¯ä¸ä¼ä¸»å¨ç»æçï¼æä»¥ï¼threadLocalçå
åæ³æ¼é®é¢ï¼æ¯åºè¯¥å¼å¾æä»¬æèåæ³¨æçé®é¢ï¼å
³äºè¿ä¸ªé®é¢å¯ä»¥çè¿ç¯æç« :
>----[详解threadLocalå
åæ³æ¼é®é¢](http://www.jianshu.com/p/dde92ec37bd1)
### setæ¹æ³
ä¸concurrentHashMapï¼hashMapç容å¨ä¸æ ·ï¼threadLocalMap乿¯éç¨æ£å表è¿è¡å®ç°çãå¨äºè§£setæ¹æ³åï¼æä»¬å
æ¥å顾ä¸å
³äºæ£å表ç¸å
³çç¥è¯ã
#### æ£å表
çæ³ç¶æä¸ï¼æ£å表就æ¯ä¸ä¸ªå
å«å
³é®åçåºå®å¤§å°çæ°ç»ï¼éè¿ä½¿ç¨æ£å彿°ï¼å°å
³é®åæ å°å°æ°ç»çä¸åä½ç½®ãä¸é¢æ¯

å¨çæ³ç¶æä¸ï¼åå¸å½æ°å¯ä»¥å°å
³é®åååç忣尿°ç»çä¸åä½ç½®ï¼ä¸ä¼åºç°ä¸¤ä¸ªå
³é®åæ£åå¼ç¸åï¼å设å
³é®åæ°éå°äºæ°ç»ç大å°ï¼çæ
åµã
使¯å¨å®é
使ç¨ä¸ï¼ç»å¸¸ä¼åºç°å¤ä¸ªå
³é®åæ£åå¼ç¸åçæ
åµï¼è¢«æ å°å°æ°ç»çåä¸ä¸ªä½ç½®ï¼ï¼æä»¬å°è¿ç§æ
åµç§°ä¸ºæ£åå²çªã
为äºè§£å³æ£åå²çªï¼ä¸»è¦éç¨ä¸é¢ä¸¤ç§æ¹å¼ï¼ **å离é¾è¡¨æ³**ï¼separate chainingï¼å**弿¾å®åæ³**ï¼open addressingï¼
##### å离é¾è¡¨æ³
忣é¾è¡¨æ³ä½¿ç¨é¾è¡¨è§£å³å²çªï¼å°æ£åå¼ç¸åçå
ç´ é½ä¿åå°ä¸ä¸ªé¾è¡¨ä¸ã彿¥è¯¢çæ¶åï¼é¦å
æ¾å°å
ç´ æå¨çé¾è¡¨ï¼ç¶åéåé¾è¡¨æ¥æ¾å¯¹åºçå
ç´ ï¼å
¸åå®ç°ä¸ºhashMapï¼concurrentHashMapçæé¾æ³ãä¸é¢æ¯ä¸ä¸ªç¤ºæå¾ï¼

##### 弿¾å®åæ³
弿¾å®åæ³ä¸ä¼å建é¾è¡¨ï¼å½å
³é®åæ£åå°çæ°ç»åå
å·²ç»è¢«å¦å¤ä¸ä¸ªå
³é®åå ç¨çæ¶åï¼å°±ä¼å°è¯å¨æ°ç»ä¸å¯»æ¾å
¶ä»çåå
ï¼ç´å°æ¾å°ä¸ä¸ªç©ºçåå
ã
æ¢æµæ°ç»ç©ºåå
çæ¹å¼æå¾å¤ï¼è¿éä»ç»ä¸ç§æç®åç -- çº¿æ§æ¢æµæ³ãçº¿æ§æ¢æµæ³å°±æ¯ä»å²çªçæ°ç»åå
å¼å§ï¼ä¾æ¬¡å¾åæç´¢ç©ºåå
ï¼å¦æå°æ°ç»å°¾é¨ï¼åä»å¤´å¼å§æç´¢ï¼ç¯å½¢æ¥æ¾ï¼ãå¦ä¸å¾æç¤ºï¼

å
³äºä¸¤ç§æ¹å¼çæ¯è¾ï¼å¯ä»¥åè [è¿ç¯æç« ](http://www.nowamagic.net/academy/detail/3008060)ã
**ThreadLocalMap ä¸ä½¿ç¨å¼æ¾å°åæ³æ¥å¤çæ£åå²çª**ï¼è HashMap ä¸ä½¿ç¨çå离é¾è¡¨æ³ã乿以éç¨ä¸åçæ¹å¼ä¸»è¦æ¯å 为ï¼
>å¨ ThreadLocalMap ä¸çæ£åå¼åæ£çååååï¼å¾å°ä¼åºç°å²çªãå¹¶ä¸ ThreadLocalMap ç»å¸¸éè¦æ¸
餿 ç¨ç对象ï¼ä½¿ç¨çº¯æ°ç»æ´å æ¹ä¾¿ã
å¨äºè§£è¿äºç¸å
³ç¥è¯åæä»¬ååè¿å¤´æ¥çä¸ä¸setæ¹æ³ãsetæ¹æ³çæºç 为ï¼
```java
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;
//æ ¹æ®threadLocalçhashCodeç¡®å®Entryåºè¯¥åæ¾çä½ç½®
int i = key.threadLocalHashCode & (len-1);
//éç¨å¼æ¾å°åæ³ï¼hashå²çªçæ¶å使ç¨çº¿æ§æ¢æµ
for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) {
ThreadLocal> k = e.get();
//è¦çæ§Entry
if (k == key) {
e.value = value;
return;
}
//å½key为nullæ¶ï¼è¯´æthreadLocal强å¼ç¨å·²ç»è¢«éæ¾æï¼é£ä¹å°±æ æ³
//åéè¿è¿ä¸ªkeyè·åthreadLocalMapä¸å¯¹åºçentryï¼è¿éå°±åå¨å
åæ³æ¼çå¯è½æ§
if (k == null) {
//ç¨å½åæå
¥ç弿¿æ¢æè¿ä¸ªkey为nullçâèâentry
replaceStaleEntry(key, value, i);
return;
}
}
//æ°å»ºentryå¹¶æå
¥tableä¸iå¤
tab[i] = new Entry(key, value);
int sz = ++size;
//æå
¥å忬¡æ¸
é¤ä¸äºkey为nullçâèâentry,妿大äºéå¼å°±éè¦æ©å®¹
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}
```
setæ¹æ³çå
³é®é¨å**请çä¸é¢ç注é**ï¼ä¸»è¦æè¿æ ·å ç¹éè¦æ³¨æï¼
#### threadLocalçhashcode?
```java
private final int threadLocalHashCode = nextHashCode();
private static final int HASH_INCREMENT = 0x61c88647;
private static AtomicInteger nextHashCode =new AtomicInteger();
/**
* Returns the next hash code.
*/
private static int nextHashCode() {
return nextHashCode.getAndAdd(HASH_INCREMENT);
}
```
仿ºç 䏿们å¯ä»¥æ¸
æ¥ççå°threadLocalå®ä¾çhashCodeæ¯éè¿nextHashCode()æ¹æ³å®ç°çï¼è¯¥æ¹æ³å®é
䏿»æ¯ç¨ä¸ä¸ªAtomicIntegerå ä¸0x61c88647æ¥å®ç°çã
0x61c88647è¿ä¸ªæ°æ¯æç¹æ®æä¹çï¼å®è½å¤ä¿è¯hashè¡¨çæ¯ä¸ªæ£åæ¡¶è½å¤ååçåå¸ï¼è¿æ¯`Fibonacci Hashing`ï¼å
³äºæ´å¤ä»ç»å¯ä»¥ç[è¿ç¯æç« çthreadLocalæ£åå¼é¨å](https://www.cnblogs.com/zhangjk1993/archive/2017/03/29/6641745.html)ã
乿£æ¯è½å¤åååå¸ï¼æä»¥threadLocaléæ©ä½¿ç¨å¼æ¾å°åæ³æ¥è§£å³hashå²çªçé®é¢ã
#### ææ ·ç¡®å®æ°å¼æå
¥å°åå¸è¡¨ä¸çä½ç½®ï¼
该æä½æºç 为ï¼`key.threadLocalHashCode & (len-1)`ï¼åhashMapåConcurrentHashMapç容å¨çæ¹å¼ä¸æ ·ï¼å©ç¨å½åkey(å³threadLocalå®ä¾)çhashcodeä¸åå¸è¡¨å¤§å°ç¸ä¸ï¼å 为åå¸è¡¨å¤§å°æ»æ¯ä¸º2ç广¬¡æ¹ï¼æä»¥ç¸ä¸çåäºä¸ä¸ªå模çè¿ç¨ï¼è¿æ ·å°±å¯ä»¥éè¿Keyåé
å°å
·ä½çå叿¡¶ä¸å»ãèè³äºä¸ºä»ä¹å模è¦éè¿ä½ä¸è¿ç®çåå å°±æ¯ä½è¿ç®çæ§è¡æçè¿è¿é«äºäºå模è¿ç®ã
#### ææ ·è§£å³hashå²çªï¼
æºç ä¸éè¿`nextIndex(i, len)`æ¹æ³è§£å³hashå²çªçé®é¢ï¼è¯¥æ¹æ³ä¸º`((i + 1 < len) ? i + 1 : 0);`ï¼ä¹å°±æ¯ä¸æå¾åçº¿æ§æ¢æµï¼å½å°åå¸è¡¨æ«å°¾çæ¶ååä»0å¼å§ï¼æç¯å½¢ã
#### ææ ·è§£å³âèâEntryï¼
å¨åæthreadLocal,threadLocalMap以åEntryçå
³ç³»çæ¶åï¼æä»¬å·²ç»ç¥é使ç¨threadLocalæå¯è½åå¨å
åæ³æ¼ï¼å¯¹è±¡åå»ºåºæ¥åï¼å¨ä¹åçé»è¾ä¸ç´æ²¡æä½¿ç¨è¯¥å¯¹è±¡ï¼ä½æ¯åå¾åæ¶å¨æ æ³åæ¶è¿ä¸ªé¨åçå
åï¼ï¼å¨æºç ä¸é对è¿ç§key为nullçEntryç§°ä¹ä¸ºâstale entryâï¼ç´è¯ä¸ºä¸æ°é²çentryï¼ææå®ç解为âèentryâï¼èªç¶èç¶ï¼Josh Bloch and Doug Lea大å¸èèå°äºè¿ç§æ
åµ,å¨setæ¹æ³çfor循ç¯ä¸å¯»æ¾åå½åKeyç¸åçå¯è¦çentryçè¿ç¨ä¸éè¿**replaceStaleEntry**æ¹æ³è§£å³èentryçé®é¢ã
妿å½å`table[i]`为nullçè¯ï¼ç´æ¥æå
¥æ°entryåä¹ä¼éè¿**cleanSomeSlots**æ¥è§£å³èentryçé®é¢ï¼å
³äºcleanSomeSlotsåreplaceStaleEntryæ¹æ³ï¼ä¼å¨è¯¦è§£threadLocalå
åæ³æ¼ä¸è®²å°ï¼å
·ä½å¯ç[è¿ç¯æç« ](http://www.jianshu.com/p/dde92ec37bd1)
#### å¦ä½è¿è¡æ©å®¹ï¼
> thresholdçç¡®å®
ä¹å ä¹å大夿°å®¹å¨ä¸æ ·ï¼threadLocalMap伿æ©å®¹æºå¶ï¼é£ä¹å®çthresholdåæ¯ææ ·ç¡®å®çäºï¼
```java
private int threshold; // Default to 0
/**
* The initial capacity -- MUST be a power of two.
*/
private static final int INITIAL_CAPACITY = 16;
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);
}
/**
* Set the resize threshold to maintain at worst a 2/3 load factor.
*/
private void setThreshold(int len) {
threshold = len * 2 / 3;
}
```
æ ¹æ®æºç å¯ç¥ï¼å¨ç¬¬ä¸æ¬¡ä¸ºthreadLocalè¿è¡èµå¼çæ¶åä¼å建åå§å¤§å°ä¸º16çthreadLocalMap,å¹¶ä¸éè¿setThresholdæ¹æ³è®¾ç½®thresholdï¼å
¶å¼ä¸ºå½åå叿°ç»é¿åº¦ä¹ä»¥ï¼2/3ï¼ï¼ä¹å°±æ¯è¯´å è½½å å为2/3(å è½½å åæ¯è¡¡éåå¸è¡¨å¯éç¨åº¦çä¸ä¸ªåæ°ï¼å¦æå è½½å åè¶å¤§çè¯ï¼è¯´æåå¸è¡¨è¢«è£
è½½çè¶å¤ï¼åºç°hashå²çªçå¯è½æ§è¶å¤§ï¼åä¹ï¼å被è£
è½½çè¶å°ï¼åºç°hashå²çªçå¯è½æ§è¶å°ã
忶妿è¿å°ï¼å¾æ¾ç¶å
å使ç¨çä¸é«ï¼è¯¥å¼åå¼åºè¯¥èèå°å
å使ç¨çåhashå²çªæ¦ççä¸ä¸ªå¹³è¡¡ï¼å¦hashMap,concurrentHashMapçå è½½å åé½ä¸º0.75)ã
è¿é**threadLocalMapåå§å¤§å°ä¸º16**ï¼**å è½½å å为2/3**ï¼æä»¥åå¸è¡¨å¯ç¨å¤§å°ä¸ºï¼16*2/3=10ï¼å³åå¸è¡¨å¯ç¨å®¹é为10ã
> æ©å®¹resize
ä»setæ¹æ³ä¸å¯ä»¥çåºå½hash表çsize大äºthresholdçæ¶åï¼ä¼éè¿resizeæ¹æ³è¿è¡æ©å®¹ã
```java
/**
* Double the capacity of the table.
*/
private void resize() {
Entry[] oldTab = table;
int oldLen = oldTab.length;
//æ°æ°ç»ä¸ºåæ°ç»ç2å
int newLen = oldLen * 2;
Entry[] newTab = new Entry[newLen];
int count = 0;
for (int j = 0; j < oldLen; ++j) {
Entry e = oldTab[j];
if (e != null) {
ThreadLocal> k = e.get();
//éåè¿ç¨ä¸å¦æéå°èentryçè¯ç´æ¥å¦value为null,æå©äºvalueè½å¤è¢«åæ¶
if (k == null) {
e.value = null; // Help the GC
} else {
//éæ°ç¡®å®entry卿°æ°ç»çä½ç½®ï¼ç¶åè¿è¡æå
¥
int h = k.threadLocalHashCode & (newLen - 1);
while (newTab[h] != null)
h = nextIndex(h, newLen);
newTab[h] = e;
count++;
}
}
}
//设置æ°åå¸è¡¨çthreshHoldåsize屿§
setThreshold(newLen);
size = count;
table = newTab;
}
```
æ¹æ³é»è¾**è¯·çæ³¨é**ï¼æ°å»ºä¸ä¸ªå¤§å°ä¸ºåæ¥æ°ç»é¿åº¦ç两åçæ°ç»ï¼ç¶åéåæ§æ°ç»ä¸çentryå¹¶å°å
¶æå
¥å°æ°çhashæ°ç»ä¸ï¼ä¸»è¦æ³¨æçæ¯ï¼**卿©å®¹çè¿ç¨ä¸é对èentryçè¯ä¼ä»¤value为nullï¼ä»¥ä¾¿è½å¤è¢«åå¾åæ¶å¨è½å¤åæ¶ï¼è§£å³éèçå
åæ³æ¼çé®é¢**ã
### getEntryæ¹æ³
getEntryæ¹æ³æºç 为ï¼
```java
private Entry getEntry(ThreadLocal> key) {
//1. ç¡®å®å¨æ£åæ°ç»ä¸çä½ç½®
int i = key.threadLocalHashCode & (table.length - 1);
//2. æ ¹æ®ç´¢å¼iè·åentry
Entry e = table[i];
//3. 满足æ¡ä»¶åè¿å该entry
if (e != null && e.get() == key)
return e;
else
//4. æªæ¥æ¾å°æ»¡è¶³æ¡ä»¶çentryï¼é¢å¤å¨åçå¤ç
return getEntryAfterMiss(key, i, e);
}
```
æ¹æ³é»è¾å¾ç®åï¼è¥è½å½åå®ä½çentryçkey忥æ¾çkeyç¸åçè¯å°±ç´æ¥è¿åè¿ä¸ªentryï¼å¦åçè¯å°±æ¯å¨setçæ¶ååå¨hashå²çªçæ
åµï¼éè¦éè¿getEntryAfterMissåè¿ä¸æ¥å¤çãgetEntryAfterMissæ¹æ³ä¸ºï¼
```java
private Entry getEntryAfterMiss(ThreadLocal> key, int i, Entry e) {
Entry[] tab = table;
int len = tab.length;
while (e != null) {
ThreadLocal> k = e.get();
if (k == key)
//æ¾å°åæ¥è¯¢çkeyç¸åçentryåè¿å
return e;
if (k == null)
//è§£å³èentryçé®é¢
expungeStaleEntry(i);
else
//ç»§ç»ååç¯å½¢æ¥æ¾
i = nextIndex(i, len);
e = tab[i];
}
return null;
}
```
è¿ä¸ªæ¹æ³åæ ·å¾å¥½çè§£ï¼éè¿nextIndexå¾åç¯å½¢æ¥æ¾ï¼å¦ææ¾å°åæ¥è¯¢çkeyç¸åçentryçè¯å°±ç´æ¥è¿åï¼å¦æå¨æ¥æ¾è¿ç¨ä¸éå°èentryçè¯ä½¿ç¨expungeStaleEntryæ¹æ³è¿è¡å¤çãå°ç®å为æ¢**ï¼ä¸ºäºè§£å³æ½å¨çå
åæ³æ¼çé®é¢ï¼å¨setï¼resize,getEntryè¿äºå°æ¹é½ä¼å¯¹è¿äºèentryè¿è¡å¤çï¼å¯è§ä¸ºäºå°½å¯è½è§£å³è¿ä¸ªé®é¢å 乿 æ¶æ å»é½å¨ååºåªåã**
### remove
```java
/**
* 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) {
//å°entryçkey置为null
e.clear();
//å°è¯¥entryçvalueä¹ç½®ä¸ºnull
expungeStaleEntry(i);
return;
}
}
}
```
è¯¥æ¹æ³é»è¾å¾ç®åï¼éè¿å¾åç¯å½¢æ¥æ¾å°ä¸æå®keyç¸åçentryåï¼å
éè¿clearæ¹æ³å°key置为nullåï¼ä½¿å
¶è½¬æ¢ä¸ºä¸ä¸ªèentryï¼ç¶åè°ç¨expungeStaleEntryæ¹æ³å°å
¶value置为nullï¼ä»¥ä¾¿åå¾åæ¶æ¶è½å¤æ¸
çï¼åæ¶å°table[i]置为nullã
## ThreadLocalç使ç¨åºæ¯
**ThreadLocal 䏿¯ç¨æ¥è§£å³å
±äº«å¯¹è±¡çå¤çº¿ç¨è®¿é®é®é¢ç**ï¼æ°æ®å®è´¨ä¸æ¯æ¾å¨æ¯ä¸ªthreadå®ä¾å¼ç¨çthreadLocalMap,ä¹å°±æ¯è¯´**æ¯ä¸ªä¸åç线ç¨é½æ¥æä¸å±äºèªå·±çæ°æ®å®¹å¨ï¼threadLocalMapï¼ï¼å½¼æ¤ä¸å½±å**ã
å æ¤threadLocalåªéç¨äº **å
±äº«å¯¹è±¡ä¼é æçº¿ç¨å®å
¨** çä¸å¡åºæ¯ãæ¯å¦**hibernateä¸éè¿threadLocal管çSession**å°±æ¯ä¸ä¸ªå
¸åçæ¡ä¾ï¼ä¸åç请æ±çº¿ç¨ï¼ç¨æ·ï¼æ¥æèªå·±çsession,è¥å°sessionå
±äº«åºå»è¢«å¤çº¿ç¨è®¿é®ï¼å¿
ç¶ä¼å¸¦æ¥çº¿ç¨å®å
¨é®é¢ã
ä¸é¢ï¼æä»¬èªå·±æ¥åä¸ä¸ªä¾åï¼SimpleDateFormat.parseæ¹æ³ä¼æçº¿ç¨å®å
¨çé®é¢ï¼æä»¬å¯ä»¥å°è¯ä½¿ç¨threadLocalå
è£
SimpleDateFormatï¼å°è¯¥å®ä¾ä¸è¢«å¤çº¿ç¨å
±äº«å³å¯ã
```java
public class ThreadLocalDemo {
private static ThreadLocal sdf = new ThreadLocal<>();
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 100; i++) {
executorService.submit(new DateUtil("2019-11-25 09:00:" + i % 60));
}
}
static class DateUtil implements Runnable {
private String date;
public DateUtil(String date) {
this.date = date;
}
@Override
public void run() {
if (sdf.get() == null) {
sdf.set(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
} else {
try {
Date date = sdf.get().parse(this.date);
System.out.println(date);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
}
}
```
1. 妿å½å线ç¨ä¸ææSimpleDateformat对象å®ä¾ï¼é£ä¹å°±æ°å»ºä¸ä¸ªå¹¶æå®è®¾ç½®å°å½å线ç¨ä¸ï¼å¦æå·²ç»ææï¼å°±ç´æ¥ä½¿ç¨ãå¦å¤ï¼**ä»` if (sdf.get() == null){....}else{.....}`å¯ä»¥çåºä¸ºæ¯ä¸ä¸ªçº¿ç¨åé
ä¸ä¸ªSimpleDateformat对象å®ä¾æ¯ä»åºç¨å±é¢ï¼ä¸å¡ä»£ç é»è¾ï¼å»ä¿è¯çã**
2. å¨ä¸é¢æä»¬è¯´è¿threadLocalæå¯è½åå¨å
åæ³æ¼ï¼å¨ä½¿ç¨å®ä¹åï¼æå¥½ä½¿ç¨removeæ¹æ³å°è¿ä¸ªåéç§»é¤ï¼å°±åå¨ä½¿ç¨æ°æ®åºè¿æ¥ä¸æ ·ï¼åæ¶å
³éè¿æ¥ã
---
>ç¼è¾ï¼æ²é»çäºï¼å
容大é¨åæ¥æºä»¥ä¸ä¸ä¸ªå¼æºä»åºï¼
>- [æ·±å
¥æµ
åº Java å¤çº¿ç¨](http://concurrent.redspider.group/)
>- [å¹¶åç¼ç¨ç¥è¯æ»ç»](https://github.com/CL0610/Java-concurrency)
>- [Javaå
«è¡æ](https://github.com/CoderLeixiaoshuai/java-eight-part)
