---
title: åæJavaå¹¶åé¢è¯å®ä¹ThreadLocal
shortTitle: ThreadLocal
description: åæJavaå¹¶åé¢è¯å®ä¹ThreadLocal
category:
- Javaæ ¸å¿
tag:
- Javaå¹¶åç¼ç¨
head:
- - meta
- name: keywords
content: Java,å¹¶åç¼ç¨,å¤çº¿ç¨,Thread,ThreadLocal
---
## ThreadLocal çç®ä»
å¨å¤çº¿ç¨ç¼ç¨ä¸é常解å³çº¿ç¨å®å
¨çé®é¢æ¶ï¼æä»¬ä¼å©ç¨ synchronzed æè
lock æ§å¶çº¿ç¨å¯¹ä¸´çåºèµæºçåæ¥é¡ºåºï¼ä½æ¯è¿ç§å éçæ¹å¼ä¼è®©æªè·åå°éç线ç¨è¿è¡é»å¡çå¾
ï¼å¾æ¾ç¶è¿ç§æ¹å¼çæ¶é´æç并䏿¯ç¹å«å¥½ã
**线ç¨å®å
¨é®é¢çæ ¸å¿å¨äºå¤ä¸ªçº¿ç¨ä¼å¯¹åä¸ä¸ªä¸´çåºå
±äº«èµæºè¿è¡æä½**ï¼é£ä¹ï¼å¦ææ¯ä¸ªçº¿ç¨é½ä½¿ç¨èªå·±çâå
±äº«èµæºâï¼åèªä½¿ç¨åèªçï¼äºç¸ä¸å½±åå°å½¼æ¤ï¼å³å¤ä¸ªçº¿ç¨é´è¾¾å°é离çç¶æï¼è¿æ ·å°±ä¸ä¼åºç°çº¿ç¨å®å
¨çé®é¢ã
äºå®ä¸ï¼è¿å°±æ¯ä¸ç§â**ç©ºé´æ¢æ¶é´**âçæ¹æ¡ï¼æ¯ä¸ªçº¿ç¨é½æ¥æèªå·±çâå
±äº«èµæºâæ çä¼è®©å
åå ç¨å¤§å¾å¤ï¼ä½æ¯ç±äºä¸éè¦åæ¥ä¹å°±åå°äºçº¿ç¨å¯è½åå¨çé»å¡çå¾
ï¼ä»èæé«æ¶é´æçã
è½ç¶ ThreadLocal å¹¶ä¸å¨ java.util.concurrent å
ä¸èå¨ java.lang å
ä¸ï¼ä½ææ´å¾åäºæå®å½ä½æ¯ä¸ç§å¹¶å容å¨ï¼è½ç¶çæ£åæ¾æ°æ®çæ¯ ThreadLocalMapï¼è¿è¡å½ç±»ã
顾åæä¹ï¼**ThreadLocal 表示线ç¨çâæ¬å°åéâï¼å³æ¯ä¸ªçº¿ç¨é½æ¥æè¯¥åé坿¬ï¼è¾¾å°äººæä¸ä»½çææï¼åç¨åçï¼è¿æ ·å°±å¯ä»¥é¿å
å
±äº«èµæºçç«äº**ã
## ThreadLocal çå®ç°åç
è¦æ³å¦ä¹ ThreadLocal çå®ç°åçï¼å°±å¿
é¡»äºè§£å®çå ä¸ªæ ¸å¿æ¹æ³ï¼å
æ¬ææ ·åææ ·åççï¼ä¸é¢æä»¬ä¸ä¸ªä¸ªæ¥çã
### set() æ¹æ³
**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,å以å½åThreadLocalå®ä¾ä¸º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)`æ¹æ³ new åºæ¥ä¸ä¸ªï¼
```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 çé®å¼å¯¹åå
¥å³å¯ã
### 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ã
### remove() æ¹æ³
```java
public void remove() {
//1. è·åå½å线ç¨çThreadLocalMap
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
//2. ä»mapä¸å é¤ä»¥å½åThreadLocalå®ä¾ä¸ºkeyçé®å¼å¯¹
m.remove(this);
}
```
getãset æ¹æ³å®ç°äºåæ°æ®åè¯»æ°æ®çæä½ï¼remove æ¹æ³å®ç°äºå¦ä½å æ°æ®çæä½ãå 餿°æ®å½ç¶æ¯ä» map ä¸å 餿°æ®ï¼å
è·åä¸å½å线ç¨ç¸å
³èç ThreadLocalMapï¼ç¶åä» map ä¸å é¤è¯¥ ThreadLocal å®ä¾ä¸º key çé®å¼å¯¹å³å¯ã
## ThreadLocalMap 详解
ä»ä¸é¢ç忿们已ç»ç¥éï¼æ°æ®å
¶å®é½æ¾å¨äº ThreadLocalMap ä¸ï¼ThreadLocal ç getãset å remove æ¹æ³å®é
ä¸é½æ¯éè¿ ThreadLocalMap ç getEntryãset å remove æ¹æ³å®ç°çã妿æ³çæ£å
¨æ¹ä½ç弿 ThreadLocalï¼å¿å¿
å¾å对 ThreadLocalMap åä¸çªçè§£ã
### Entry æ°æ®ç»æ
ThreadLocalMap æ¯ ThreadLocal ä¸ä¸ªéæå
é¨ç±»ï¼å大夿°å®¹å¨ä¸æ ·ï¼å
é¨ç»´æ¤äºä¸ä¸ªæ°ç»ï¼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 å 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 æ¹æ³å°è¿ä¸ªåéç§»é¤ï¼å°±åå¨ä½¿ç¨æ°æ®åºè¿æ¥ä¸æ ·ï¼åæ¶å
³éè¿æ¥ã
---
> ç¼è¾ï¼æ²é»çäºï¼æ´å¤å
³äºå¹¶åç¼ç¨çæºç åæï¼å¯ä»¥åè[å¹¶åç¼ç¨ç¥è¯æ»ç»](https://github.com/CL0610/Java-concurrency)è¿ä¸ªå¼æºç¥è¯åºã
---
æè¿æ´çäºä¸ä»½çé¼çå¦ä¹ èµæï¼å
æ¬ä½ä¸éäº Java åºç¡é¨åï¼JVMãJava éåæ¡æ¶ãå¤çº¿ç¨ï¼ï¼è¿åæ¬äº **æ°æ®åºãè®¡ç®æºç½ç»ãç®æ³ä¸æ°æ®ç»æã设计模å¼ãæ¡æ¶ç±» SpringãNettyãå¾®æå¡ï¼Dubboï¼æ¶æ¯éåï¼ ç½å
³** ççççâ¦â¦è¯¦æ
æ³ï¼[å¯ä»¥è¯´æ¯ 2022 å¹´å
¨ç½æå
¨çå¦ä¹ 忾工ä½ç PDF èµæºäº](https://tobebetterjavaer.com/pdf/programmer-111.html)
å
³æ³¨äºå¥çååå
¬ä¼å· **æ²é»çäº**ï¼åå¤**111** å³å¯å
è´¹é¢åã
