> æ¬ææ¥èªä¸æè±ç®ä¸ç®æµªæ¼«æç¨¿ï¼ åæå°åï¼[https://juejin.im/post/5eacc1c75188256d976df748](https://juejin.im/post/5eacc1c75188256d976df748)ã
### åè¨

**å
¨æå
±10000+åï¼31å¼ å¾ï¼è¿ç¯æç« åæ ·èè´¹äºä¸å°çæ¶é´åç²¾åæåä½å®æï¼åå䏿ï¼è¯·å¤§å®¶ç¹ç¹å
³æ³¨+å¨çï¼æè°¢ã**
对äº`ThreadLocal`ï¼å¤§å®¶ç第ä¸ååºå¯è½æ¯å¾ç®ååï¼çº¿ç¨çåé坿¬ï¼æ¯ä¸ªçº¿ç¨é离ãé£è¿éæå 个é®é¢å¤§å®¶å¯ä»¥æèä¸ä¸ï¼
- `ThreadLocal`çkeyæ¯**å¼±å¼ç¨**ï¼é£ä¹å¨ `ThreadLocal`.get()çæ¶å,åç**GC**ä¹åï¼keyæ¯å¦ä¸º**null**ï¼
- `ThreadLocal`ä¸`ThreadLocalMap`ç**æ°æ®ç»æ**ï¼
- `ThreadLocalMap`ç**Hashç®æ³**ï¼
- `ThreadLocalMap`ä¸**Hashå²çª**å¦ä½è§£å³ï¼
- `ThreadLocalMap`ç**æ©å®¹æºå¶**ï¼
- `ThreadLocalMap`ä¸**è¿ækeyçæ¸
çæºå¶**ï¼**æ¢æµå¼æ¸
ç**å**å¯å弿¸
ç**æµç¨ï¼
- `ThreadLocalMap.set()`æ¹æ³å®ç°åçï¼
- `ThreadLocalMap.get()`æ¹æ³å®ç°åçï¼
- 项ç®ä¸`ThreadLocal`ä½¿ç¨æ
åµï¼éå°çåï¼
- ......
ä¸è¿°çä¸äºé®é¢ä½ æ¯å¦é½å·²ç»ææ¡ç徿¸
æ¥äºå¢ï¼æ¬æå°å´ç»è¿äºé®é¢ä½¿ç¨å¾ææ¹å¼æ¥åæ`ThreadLocal`ç**ç¹ç¹æ»´æ»´**ã
### ç®å½
**注æï¼** æ¬ææºç åºäº`JDK 1.8`
### `ThreadLocal`ä»£ç æ¼ç¤º
æä»¬å
çä¸`ThreadLocal`使ç¨ç¤ºä¾ï¼
```java
public class ThreadLocalTest {
private List messages = Lists.newArrayList();
public static final `ThreadLocal` holder = `ThreadLocal`.withInitial(ThreadLocalTest::new);
public static void add(String message) {
holder.get().messages.add(message);
}
public static List clear() {
List messages = holder.get().messages;
holder.remove();
System.out.println("size: " + holder.get().messages.size());
return messages;
}
public static void main(String[] args) {
ThreadLocalTest.add("䏿è±ç®ä¸ç®æµªæ¼«");
System.out.println(holder.get().messages);
ThreadLocalTest.clear();
}
}
```
æå°ç»æï¼
```java
[䏿è±ç®ä¸ç®æµªæ¼«]
size: 0
```
`ThreadLocal`对象å¯ä»¥æä¾çº¿ç¨å±é¨åéï¼æ¯ä¸ªçº¿ç¨`Thread`æ¥æä¸ä»½èªå·±ç**坿¬åé**ï¼å¤ä¸ªçº¿ç¨äºä¸å¹²æ°ã
### `ThreadLocal`çæ°æ®ç»æ

`Thread`ç±»æä¸ä¸ªç±»å为``ThreadLocal`.`ThreadLocalMap``çå®ä¾åé`threadLocals`ï¼ä¹å°±æ¯è¯´æ¯ä¸ªçº¿ç¨æä¸ä¸ªèªå·±ç`ThreadLocalMap`ã
`ThreadLocalMap`æèªå·±çç¬ç«å®ç°ï¼å¯ä»¥ç®åå°å°å®ç`key`è§ä½`ThreadLocal`ï¼`value`为代ç 䏿¾å
¥çå¼ï¼å®é
ä¸`key`并䏿¯`ThreadLocal`æ¬èº«ï¼èæ¯å®çä¸ä¸ª**å¼±å¼ç¨**ï¼ã
æ¯ä¸ªçº¿ç¨å¨å¾`ThreadLocal`éæ¾å¼çæ¶åï¼é½ä¼å¾èªå·±ç`ThreadLocalMap`éåï¼è¯»ä¹æ¯ä»¥`ThreadLocal`ä½ä¸ºå¼ç¨ï¼å¨èªå·±ç`map`鿾坹åºç`key`ï¼ä»èå®ç°äº**线ç¨é离**ã
`ThreadLocalMap`æç¹ç±»ä¼¼`HashMap`çç»æï¼åªæ¯`HashMap`æ¯ç±**æ°ç»+é¾è¡¨**å®ç°çï¼è`ThreadLocalMap`ä¸å¹¶æ²¡æ**é¾è¡¨**ç»æã
æä»¬è¿è¦æ³¨æ`Entry`ï¼ å®ç`key`æ¯``ThreadLocal`> k` ï¼ç»§æ¿èª`WeakReferenceï¼ ä¹å°±æ¯æä»¬å¸¸è¯´çå¼±å¼ç¨ç±»åã
### GC ä¹åkeyæ¯å¦ä¸ºnullï¼
ååºå¼å¤´çé£ä¸ªé®é¢ï¼ `ThreadLocal` ç`key`æ¯å¼±å¼ç¨ï¼é£ä¹å¨` `ThreadLocal`.get()`çæ¶å,åç`GC`ä¹åï¼`key`æ¯å¦æ¯`null`ï¼
ä¸ºäºææ¸
æ¥è¿ä¸ªé®é¢ï¼æä»¬éè¦ææ¸
æ¥`Java`ç**åç§å¼ç¨ç±»å**ï¼
- **强å¼ç¨**ï¼æä»¬å¸¸å¸¸newåºæ¥ç对象就æ¯å¼ºå¼ç¨ç±»åï¼åªè¦å¼ºå¼ç¨åå¨ï¼åå¾åæ¶å¨å°æ°¸è¿ä¸ä¼åæ¶è¢«å¼ç¨ç对象ï¼åªæå
åä¸è¶³çæ¶å
- **软å¼ç¨**ï¼ä½¿ç¨SoftReference修饰ç对象被称为软å¼ç¨ï¼è½¯å¼ç¨æåç对象å¨å
åè¦æº¢åºçæ¶åè¢«åæ¶
- **å¼±å¼ç¨**ï¼ä½¿ç¨WeakReference修饰ç对象被称为弱å¼ç¨ï¼åªè¦åçåå¾åæ¶ï¼è¥è¿ä¸ªå¯¹è±¡åªè¢«å¼±å¼ç¨æåï¼é£ä¹å°±ä¼è¢«åæ¶
- **èå¼ç¨**ï¼èå¼ç¨æ¯æå¼±çå¼ç¨ï¼å¨ Java ä¸ä½¿ç¨ PhantomReference è¿è¡å®ä¹ãèå¼ç¨ä¸å¯ä¸çä½ç¨å°±æ¯ç¨é忥æ¶å¯¹è±¡å³å°æ»äº¡çéç¥
æ¥ç忥çä¸ä»£ç ï¼æä»¬ä½¿ç¨åå°çæ¹å¼æ¥çç`GC`å`ThreadLocal`ä¸çæ°æ®æ
åµï¼(ä¸é¢ä»£ç æ¥æºèªï¼https://blog.csdn.net/thewindkee/article/details/103726942ï¼æ¬å°è¿è¡æ¼ç¤ºGCåæ¶åºæ¯)
```java
public class ThreadLocalDemo {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, InterruptedException {
Thread t = new Thread(()->test("abc",false));
t.start();
t.join();
System.out.println("--gcå--");
Thread t2 = new Thread(() -> test("def", true));
t2.start();
t2.join();
}
private static void test(String s,boolean isGC) {
try {
new `ThreadLocal`().set(s);
if (isGC) {
System.gc();
}
Thread t = Thread.currentThread();
Class extends Thread> clz = t.getClass();
Field field = clz.getDeclaredField("threadLocals");
field.setAccessible(true);
Object `ThreadLocalMap` = field.get(t);
Class> tlmClass = `ThreadLocalMap`.getClass();
Field tableField = tlmClass.getDeclaredField("table");
tableField.setAccessible(true);
Object[] arr = (Object[]) tableField.get(`ThreadLocalMap`);
for (Object o : arr) {
if (o != null) {
Class> entryClass = o.getClass();
Field valueField = entryClass.getDeclaredField("value");
Field referenceField = entryClass.getSuperclass().getSuperclass().getDeclaredField("referent");
valueField.setAccessible(true);
referenceField.setAccessible(true);
System.out.println(String.format("å¼±å¼ç¨key:%s,å¼:%s", referenceField.get(o), valueField.get(o)));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
```
ç»æå¦ä¸ï¼
```java
å¼±å¼ç¨key:java.lang.`ThreadLocal`@433619b6,å¼:abc
å¼±å¼ç¨key:java.lang.`ThreadLocal`@418a15e3,å¼:java.lang.ref.SoftReference@bf97a12
--gcå--
å¼±å¼ç¨key:null,å¼:def
```

å¦å¾æç¤ºï¼å 为è¿éå建ç`ThreadLocal`并没ææåä»»ä½å¼ï¼ä¹å°±æ¯æ²¡æä»»ä½å¼ç¨ï¼
```java
new ThreadLocal().set(s);
```
æä»¥è¿éå¨`GC`ä¹åï¼`key`å°±ä¼è¢«åæ¶ï¼æä»¬çå°ä¸é¢`debug`ä¸ç`referent=null`, 妿**æ¹å¨ä¸ä¸ä»£ç ï¼**

è¿ä¸ªé®é¢åå¼å§çï¼å¦ææ²¡æè¿å¤æèï¼**å¼±å¼ç¨**ï¼è¿æ**åå¾åæ¶**ï¼é£ä¹è¯å®ä¼è§å¾æ¯`null`ã
å
¶å®æ¯ä¸å¯¹çï¼å 为é¢ç®è¯´çæ¯å¨å ``ThreadLocal`.get()` æä½ï¼è¯æå
¶å®è¿æ¯æ**强å¼ç¨**åå¨çï¼æä»¥ `key` å¹¶ä¸ä¸º `null`ï¼å¦ä¸å¾æç¤ºï¼`ThreadLocal`ç**强å¼ç¨**ä»ç¶æ¯åå¨çã

妿æä»¬ç**强å¼ç¨**ä¸åå¨çè¯ï¼é£ä¹ `key` å°±ä¼è¢«åæ¶ï¼ä¹å°±æ¯ä¼åºç°æä»¬ `value` æ²¡è¢«åæ¶ï¼`key` è¢«åæ¶ï¼å¯¼è´ `value` æ°¸è¿åå¨ï¼åºç°å
åæ³æ¼ã
### `ThreadLocal.set()`æ¹æ³æºç 详解

`ThreadLocal`ä¸ç`set`æ¹æ³åçå¦ä¸å¾æç¤ºï¼å¾ç®åï¼ä¸»è¦æ¯å¤æ`ThreadLocalMap`æ¯å¦åå¨ï¼ç¶å使ç¨`ThreadLocal`ä¸ç`set`æ¹æ³è¿è¡æ°æ®å¤çã
代ç å¦ä¸ï¼
```java
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
void createMap(Thread t, T firstValue) {
t.threadLocals = new `ThreadLocalMap`(this, firstValue);
}
```
主è¦çæ ¸å¿é»è¾è¿æ¯å¨`ThreadLocalMap`ä¸çï¼ä¸æ¥æ¥å¾ä¸çï¼åé¢è¿ææ´è¯¦ç»çåæã
### `ThreadLocalMap` Hashç®æ³
æ¢ç¶æ¯`Map`ç»æï¼é£ä¹`ThreadLocalMap`å½ç¶ä¹è¦å®ç°èªå·±ç`hash`ç®æ³æ¥è§£å³æ£å表æ°ç»å²çªé®é¢ã
```java
int i = key.threadLocalHashCode & (len-1);
```
`ThreadLocalMap`ä¸`hash`ç®æ³å¾ç®åï¼è¿é`i`å°±æ¯å½åkey卿£å表ä¸å¯¹åºçæ°ç»ä¸æ ä½ç½®ã
è¿éæå
³é®çå°±æ¯`threadLocalHashCode`å¼ç计ç®ï¼`ThreadLocal`䏿ä¸ä¸ªå±æ§ä¸º`HASH_INCREMENT = 0x61c88647`
```java
public class ThreadLocal {
private final int threadLocalHashCode = nextHashCode();
private static AtomicInteger nextHashCode = new AtomicInteger();
private static final int HASH_INCREMENT = 0x61c88647;
private static int nextHashCode() {
return nextHashCode.getAndAdd(HASH_INCREMENT);
}
static class `ThreadLocalMap` {
`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`对象ï¼è¿ä¸ª``ThreadLocal`.nextHashCode` è¿ä¸ªå¼å°±ä¼å¢é¿ `0x61c88647` ã
è¿ä¸ªå¼å¾ç¹æ®ï¼å®æ¯**ææ³¢é£å¥æ°** ä¹å« **é»éå岿°**ã`hash`å¢é为 è¿ä¸ªæ°åï¼å¸¦æ¥ç好å¤å°±æ¯ `hash` **åå¸é常åå**ã
æä»¬èªå·±å¯ä»¥å°è¯ä¸ï¼

å¯ä»¥çå°äº§ççåå¸ç åå¸å¾ååï¼è¿éä¸å»ç»çº **ææ³¢é£å¥**å
·ä½ç®æ³ï¼æå
´è¶£çå¯ä»¥èªè¡æ¥é
ç¸å
³èµæã
### `ThreadLocalMap` Hashå²çª
> **注æï¼** ä¸é¢ææç¤ºä¾å¾ä¸ï¼**绿è²å**`Entry`代表**æ£å¸¸æ°æ®**ï¼**ç°è²å**代表`Entry`ç`key`å¼ä¸º`null`ï¼**已被åå¾åæ¶**ã**ç½è²å**表示`Entry`为`null`ã
è½ç¶`ThreadLocalMap`ä¸ä½¿ç¨äº**é»éåéæ°æ¥**ä½ä¸º`hash`计ç®å åï¼å¤§å¤§åå°äº`Hash`å²çªçæ¦çï¼ä½æ¯ä»ç¶ä¼åå¨å²çªã
`HashMap`ä¸è§£å³å²çªçæ¹æ³æ¯å¨æ°ç»ä¸æé ä¸ä¸ª**é¾è¡¨**ç»æï¼å²çªçæ°æ®æè½½å°é¾è¡¨ä¸ï¼å¦æé¾è¡¨é¿åº¦è¶
è¿ä¸å®æ°éåä¼è½¬åæ**çº¢é»æ **ã
è`ThreadLocalMap`ä¸å¹¶æ²¡æé¾è¡¨ç»æï¼æä»¥è¿éä¸è½éç¨`HashMap`è§£å³å²çªçæ¹å¼äºã

å¦ä¸å¾æç¤ºï¼å¦ææä»¬æå
¥ä¸ä¸ª`value=27`çæ°æ®ï¼éè¿`hash`计ç®ååºè¯¥è½å
¥ç¬¬4个槽ä½ä¸ï¼èæ§½ä½4å·²ç»æäº`Entry`æ°æ®ã
æ¤æ¶å°±ä¼çº¿æ§å忥æ¾ï¼ä¸ç´æ¾å°`Entry`为`null`çæ§½ä½æä¼åæ¢æ¥æ¾ï¼å°å½åå
ç´ æ¾å
¥æ¤æ§½ä½ä¸ãå½ç¶è¿ä»£è¿ç¨ä¸è¿æå
¶ä»çæ
åµï¼æ¯å¦éå°äº`Entry`ä¸ä¸º`null`ä¸`key`å¼ç¸ççæ
åµï¼è¿æ`Entry`ä¸ç`key`å¼ä¸º`null`çæ
åµççé½ä¼æä¸åçå¤çï¼åé¢ä¼ä¸ä¸è¯¦ç»è®²è§£ã
è¿éè¿ç»äºä¸ä¸ª`Entry`ä¸ç`key`为`null`çæ°æ®ï¼**Entry=2çç°è²åæ°æ®**ï¼ï¼å 为`key`弿¯**å¼±å¼ç¨**ç±»åï¼æä»¥ä¼æè¿ç§æ°æ®åå¨ãå¨`set`è¿ç¨ä¸ï¼å¦æéå°äº`key`è¿æç`Entry`æ°æ®ï¼å®é
䏿¯ä¼è¿è¡ä¸è½®**æ¢æµå¼æ¸
ç**æä½çï¼å
·ä½æä½æ¹å¼åé¢ä¼è®²å°ã
### `ThreadLocalMap.set()`详解
#### `ThreadLocalMap.set()`åçå¾è§£
çå®äº`ThreadLocal` **hashç®æ³**åï¼æä»¬åæ¥ç`set`æ¯å¦ä½å®ç°çã
å¾`ThreadLocalMap`ä¸`set`æ°æ®ï¼**æ°å¢**æè
**æ´æ°**æ°æ®ï¼å为好å ç§æ
åµï¼é对ä¸åçæ
嵿们ç»å¾æ¥è¯´è¯´æã
**第ä¸ç§æ
åµï¼** éè¿`hash`计ç®åçæ§½ä½å¯¹åºç`Entry`æ°æ®ä¸ºç©ºï¼

è¿éç´æ¥å°æ°æ®æ¾å°è¯¥æ§½ä½å³å¯ã
**第äºç§æ
åµï¼** æ§½ä½æ°æ®ä¸ä¸ºç©ºï¼`key`å¼ä¸å½å`ThreadLocal`éè¿`hash`计ç®è·åç`key`å¼ä¸è´ï¼

è¿éç´æ¥æ´æ°è¯¥æ§½ä½çæ°æ®ã
**第ä¸ç§æ
åµï¼** æ§½ä½æ°æ®ä¸ä¸ºç©ºï¼å¾åéåè¿ç¨ä¸ï¼å¨æ¾å°`Entry`为`null`çæ§½ä½ä¹åï¼æ²¡æéå°`key`è¿æç`Entry`ï¼

é忣忰ç»ï¼çº¿æ§å¾åæ¥æ¾ï¼å¦ææ¾å°`Entry`为`null`çæ§½ä½ï¼åå°æ°æ®æ¾å
¥è¯¥æ§½ä½ä¸ï¼æè
å¾åéåè¿ç¨ä¸ï¼éå°äº**keyå¼ç¸ç**çæ°æ®ï¼ç´æ¥æ´æ°å³å¯ã
**第åç§æ
åµï¼** æ§½ä½æ°æ®ä¸ä¸ºç©ºï¼å¾åéåè¿ç¨ä¸ï¼å¨æ¾å°`Entry`为`null`çæ§½ä½ä¹åï¼éå°`key`è¿æç`Entry`ï¼å¦ä¸å¾ï¼å¾åéåè¿ç¨ä¸ï¼ä¸å°äº`index=7`çæ§½ä½æ°æ®`Entry`ç`key=null`ï¼

æ£åæ°ç»ä¸æ 为7ä½ç½®å¯¹åºç`Entry`æ°æ®`key`为`null`ï¼è¡¨ææ¤æ°æ®`key`å¼å·²ç»è¢«åå¾åæ¶æäºï¼æ¤æ¶å°±ä¼æ§è¡`replaceStaleEntry()`æ¹æ³ï¼è¯¥æ¹æ³å«ä¹æ¯**æ¿æ¢è¿ææ°æ®çé»è¾**ï¼ä»¥**index=7**ä½èµ·ç¹å¼å§éåï¼è¿è¡æ¢æµå¼æ°æ®æ¸
çå·¥ä½ã
åå§åæ¢æµå¼æ¸
çè¿ææ°æ®æ«æçå¼å§ä½ç½®ï¼`slotToExpunge = staleSlot = 7`
以å½å`staleSlot`å¼å§ ååè¿ä»£æ¥æ¾ï¼æ¾å
¶ä»è¿æçæ°æ®ï¼ç¶åæ´æ°è¿ææ°æ®èµ·å§æ«æä¸æ `slotToExpunge`ã`for`循ç¯è¿ä»£ï¼ç´å°ç¢°å°`Entry`为`null`ç»æã
妿æ¾å°äºè¿æçæ°æ®ï¼ç»§ç»ååè¿ä»£ï¼ç´å°éå°`Entry=null`çæ§½ä½æåæ¢è¿ä»£ï¼å¦ä¸å¾æç¤ºï¼**slotToExpungeè¢«æ´æ°ä¸º0**ï¼

以å½åèç¹(`index=7`)ååè¿ä»£ï¼æ£æµæ¯å¦æè¿æç`Entry`æ°æ®ï¼å¦ææåæ´æ°`slotToExpunge`å¼ã碰å°`null`åç»ææ¢æµã以ä¸å¾ä¸ºä¾`slotToExpunge`è¢«æ´æ°ä¸º0ã
ä¸é¢ååè¿ä»£çæä½æ¯ä¸ºäºæ´æ°æ¢æµæ¸
çè¿ææ°æ®çèµ·å§ä¸æ `slotToExpunge`çå¼ï¼è¿ä¸ªå¼å¨åé¢ä¼è®²è§£ï¼å®æ¯ç¨æ¥å¤æå½åè¿ææ§½ä½`staleSlot`ä¹åæ¯å¦è¿æè¿æå
ç´ ã
æ¥çå¼å§ä»¥`staleSlot`ä½ç½®(index=7)ååè¿ä»£ï¼**妿æ¾å°äºç¸åkeyå¼çEntryæ°æ®ï¼**

ä»å½åèç¹`staleSlot`å忥æ¾`key`å¼ç¸çç`Entry`å
ç´ ï¼æ¾å°åæ´æ°`Entry`çå¼å¹¶äº¤æ¢`staleSlot`å
ç´ çä½ç½®(`staleSlot`ä½ç½®ä¸ºè¿æå
ç´ )ï¼æ´æ°`Entry`æ°æ®ï¼ç¶åå¼å§è¿è¡è¿æ`Entry`çæ¸
çå·¥ä½ï¼å¦ä¸å¾æç¤ºï¼

**ååéåè¿ç¨ä¸ï¼å¦ææ²¡ææ¾å°ç¸åkeyå¼çEntryæ°æ®ï¼**

ä»å½åèç¹`staleSlot`å忥æ¾`key`å¼ç¸çç`Entry`å
ç´ ï¼ç´å°`Entry`为`null`å忢坻æ¾ãéè¿ä¸å¾å¯ç¥ï¼æ¤æ¶`table`䏿²¡æ`key`å¼ç¸åç`Entry`ã
å建æ°ç`Entry`ï¼æ¿æ¢`table[stableSlot]`ä½ç½®ï¼

æ¿æ¢å®æå乿¯è¿è¡è¿æå
ç´ æ¸
çå·¥ä½ï¼æ¸
çå·¥ä½ä¸»è¦æ¯æä¸¤ä¸ªæ¹æ³ï¼`expungeStaleEntry()`å`cleanSomeSlots()`ï¼å
·ä½ç»èåé¢ä¼è®²å°ï¼è¯·ç»§ç»å¾åçã
#### `ThreadLocalMap.set()`æºç 详解
ä¸é¢å·²ç»ç¨å¾çæ¹å¼è§£æäº`set()`å®ç°çåçï¼å
¶å®å·²ç»å¾æ¸
æ°äºï¼æä»¬æ¥çåç䏿ºç ï¼
`java.lang.ThreadLocal`.`ThreadLocalMap.set()`:
```java
private void set(ThreadLocal> key, Object value) {
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;
}
if (k == null) {
replaceStaleEntry(key, value, i);
return;
}
}
tab[i] = new Entry(key, value);
int sz = ++size;
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}
```
è¿éä¼éè¿`key`æ¥è®¡ç®å¨æ£å表ä¸ç对åºä½ç½®ï¼ç¶å以å½å`key`对åºçæ¡¶çä½ç½®å忥æ¾ï¼æ¾å°å¯ä»¥ä½¿ç¨çæ¡¶ã
```java
Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len-1);
```
ä»ä¹æ
åµä¸æ¡¶ææ¯å¯ä»¥ä½¿ç¨çå¢ï¼
1. `k = key` è¯´ææ¯æ¿æ¢æä½ï¼å¯ä»¥ä½¿ç¨
2. 碰å°ä¸ä¸ªè¿æçæ¡¶ï¼æ§è¡æ¿æ¢é»è¾ï¼å ç¨è¿ææ¡¶
3. æ¥æ¾è¿ç¨ä¸ï¼ç¢°å°æ¡¶ä¸`Entry=null`çæ
åµï¼ç´æ¥ä½¿ç¨
æ¥çå°±æ¯æ§è¡`for`循ç¯éåï¼å忥æ¾ï¼æä»¬å
çä¸`nextIndex()`ã`prevIndex()`æ¹æ³å®ç°ï¼

```java
private static int nextIndex(int i, int len) {
return ((i + 1 = 0) ? i - 1 : len - 1);
}
```
æ¥ççå©ä¸`for`循ç¯ä¸çé»è¾ï¼
1. éåå½å`key`å¼å¯¹åºçæ¡¶ä¸`Entry`æ°æ®ä¸ºç©ºï¼è¿è¯´ææ£åæ°ç»è¿éæ²¡ææ°æ®å²çªï¼è·³åº`for`循ç¯ï¼ç´æ¥`set`æ°æ®å°å¯¹åºçæ¡¶ä¸
2. 妿`key`å¼å¯¹åºçæ¡¶ä¸`Entry`æ°æ®ä¸ä¸ºç©º
2.1 妿`k = key`ï¼è¯´æå½å`set`æä½æ¯ä¸ä¸ªæ¿æ¢æä½ï¼åæ¿æ¢é»è¾ï¼ç´æ¥è¿å
2.2 妿`key = null`ï¼è¯´æå½åæ¡¶ä½ç½®ç`Entry`æ¯è¿ææ°æ®ï¼æ§è¡`replaceStaleEntry()`æ¹æ³(æ ¸å¿æ¹æ³)ï¼ç¶åè¿å
3. `for`å¾ªç¯æ§è¡å®æ¯ï¼ç»§ç»å¾ä¸æ§è¡è¯´æååè¿ä»£çè¿ç¨ä¸éå°äº`entry`为`null`çæ
åµ
3.1 å¨`Entry`为`null`çæ¡¶ä¸å建ä¸ä¸ªæ°ç`Entry`对象
3.2 æ§è¡`++size`æä½
4. è°ç¨`cleanSomeSlots()`å䏿¬¡å¯å弿¸
çå·¥ä½ï¼æ¸
çæ£åæ°ç»ä¸`Entry`ç`key`è¿æçæ°æ®
4.1 妿æ¸
çå·¥ä½å®æåï¼æªæ¸
çå°ä»»ä½æ°æ®ï¼ä¸`size`è¶
è¿äºéå¼(æ°ç»é¿åº¦ç2/3)ï¼è¿è¡`rehash()`æä½
4.2 `rehash()`ä¸ä¼å
è¿è¡ä¸è½®æ¢æµå¼æ¸
çï¼æ¸
çè¿æ`key`ï¼æ¸
ç宿å妿**size >= threshold - threshold / 4**ï¼å°±ä¼æ§è¡çæ£çæ©å®¹é»è¾(æ©å®¹é»è¾å¾åç)
æ¥çéç¹çä¸`replaceStaleEntry()`æ¹æ³ï¼`replaceStaleEntry()`æ¹æ³æä¾æ¿æ¢è¿ææ°æ®çåè½ï¼æä»¬å¯ä»¥å¯¹åºä¸é¢**第åç§æ
åµ**çåç徿¥åå顾ä¸ï¼å
·ä½ä»£ç å¦ä¸ï¼
`java.lang.ThreadLocal.ThreadLocalMap.replaceStaleEntry()`:
```java
private void replaceStaleEntry(`ThreadLocal`> key, Object value,
int staleSlot) {
Entry[] tab = table;
int len = tab.length;
Entry e;
int slotToExpunge = staleSlot;
for (int i = prevIndex(staleSlot, len);
(e = tab[i]) != null;
i = prevIndex(i, len))
if (e.get() == null)
slotToExpunge = i;
for (int i = nextIndex(staleSlot, len);
(e = tab[i]) != null;
i = nextIndex(i, len)) {
`ThreadLocal`> k = e.get();
if (k == key) {
e.value = value;
tab[i] = tab[staleSlot];
tab[staleSlot] = e;
if (slotToExpunge == staleSlot)
slotToExpunge = i;
cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);
return;
}
if (k == null && slotToExpunge == staleSlot)
slotToExpunge = i;
}
tab[staleSlot].value = null;
tab[staleSlot] = new Entry(key, value);
if (slotToExpunge != staleSlot)
cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);
}
```
`slotToExpunge`表示å¼å§æ¢æµå¼æ¸
çè¿ææ°æ®çå¼å§ä¸æ ï¼é»è®¤ä»å½åç`staleSlot`å¼å§ã以å½åç`staleSlot`å¼å§ï¼ååè¿ä»£æ¥æ¾ï¼æ¾å°æ²¡æè¿æçæ°æ®ï¼`for`循ç¯ä¸ç´ç¢°å°`Entry`为`null`æä¼ç»æã妿ååæ¾å°äºè¿ææ°æ®ï¼æ´æ°æ¢æµæ¸
çè¿ææ°æ®çå¼å§ä¸æ 为iï¼å³`slotToExpunge=i`
```java
for (int i = prevIndex(staleSlot, len);
(e = tab[i]) != null;
i = prevIndex(i, len)){
if (e.get() == null){
slotToExpunge = i;
}
}
```
æ¥çå¼å§ä»`staleSlot`å忥æ¾ï¼ä¹æ¯ç¢°å°`Entry`为`null`çæ¡¶ç»æã
妿è¿ä»£è¿ç¨ä¸ï¼**碰å°k == key**ï¼è¿è¯´æè¿éæ¯æ¿æ¢é»è¾ï¼æ¿æ¢æ°æ°æ®å¹¶ä¸äº¤æ¢å½å`staleSlot`ä½ç½®ã妿`slotToExpunge == staleSlot`ï¼è¿è¯´æ`replaceStaleEntry()`ä¸å¼å§å忥æ¾è¿ææ°æ®æ¶å¹¶æªæ¾å°è¿æç`Entry`æ°æ®ï¼æ¥çå忥æ¾è¿ç¨ä¸ä¹æªåç°è¿ææ°æ®ï¼ä¿®æ¹å¼å§æ¢æµå¼æ¸
çè¿ææ°æ®ç䏿 为å½å循ç¯çindexï¼å³`slotToExpunge = i`ãæåè°ç¨`cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);`è¿è¡å¯åå¼è¿ææ°æ®æ¸
çã
```java
if (k == key) {
e.value = value;
tab[i] = tab[staleSlot];
tab[staleSlot] = e;
if (slotToExpunge == staleSlot)
slotToExpunge = i;
cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);
return;
}
```
`cleanSomeSlots()`å`expungeStaleEntry()`æ¹æ³åé¢é½ä¼ç»è®²ï¼è¿ä¸¤ä¸ªæ¯åæ¸
çç¸å
³çæ¹æ³ï¼ä¸ä¸ªæ¯è¿æ`key`ç¸å
³`Entry`çå¯å弿¸
ç(`Heuristically scan`)ï¼å¦ä¸ä¸ªæ¯è¿æ`key`ç¸å
³`Entry`çæ¢æµå¼æ¸
çã
**妿k != key**å伿¥çå¾ä¸èµ°ï¼`k == null`说æå½åéåç`Entry`æ¯ä¸ä¸ªè¿ææ°æ®ï¼`slotToExpunge == staleSlot`说æï¼ä¸å¼å§çååæ¥æ¾æ°æ®å¹¶æªæ¾å°è¿æç`Entry`ã妿æ¡ä»¶æç«ï¼åæ´æ°`slotToExpunge` 为å½åä½ç½®ï¼è¿ä¸ªåææ¯å驱èç¹æ«ææ¶æªåç°è¿ææ°æ®ã
```java
if (k == null && slotToExpunge == staleSlot)
slotToExpunge = i;
```
å¾åè¿ä»£çè¿ç¨ä¸å¦ææ²¡ææ¾å°`k == key`çæ°æ®ï¼ä¸ç¢°å°`Entry`为`null`çæ°æ®ï¼åç»æå½åçè¿ä»£æä½ãæ¤æ¶è¯´æè¿éæ¯ä¸ä¸ªæ·»å çé»è¾ï¼å°æ°çæ°æ®æ·»å å°`table[staleSlot]` 对åºç`slot`ä¸ã
```java
tab[staleSlot].value = null;
tab[staleSlot] = new Entry(key, value);
```
æå夿é¤äº`staleSlot`以å¤ï¼è¿åç°äºå
¶ä»è¿æç`slot`æ°æ®ï¼å°±è¦å¼å¯æ¸
çæ°æ®çé»è¾ï¼
```java
if (slotToExpunge != staleSlot)
cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);
```
### `ThreadLocalMap`è¿ækeyçæ¢æµå¼æ¸
çæµç¨
ä¸é¢æä»¬ææå`ThreadLocalMap`ç两ç§è¿æ`key`æ°æ®æ¸
çæ¹å¼ï¼**æ¢æµå¼æ¸
ç**å**å¯å弿¸
ç**ã
æä»¬å
è®²ä¸æ¢æµå¼æ¸
çï¼ä¹å°±æ¯`expungeStaleEntry`æ¹æ³ï¼é忣忰ç»ï¼ä»å¼å§ä½ç½®ååæ¢æµæ¸
çè¿ææ°æ®ï¼å°è¿ææ°æ®ç`Entry`设置为`null`ï¼æ²¿éä¸ç¢°å°æªè¿æçæ°æ®åå°æ¤æ°æ®`rehash`åéæ°å¨`table`æ°ç»ä¸å®ä½ï¼å¦æå®ä½çä½ç½®å·²ç»æäºæ°æ®ï¼åä¼å°æªè¿æçæ°æ®æ¾å°æé è¿æ¤ä½ç½®ç`Entry=null`çæ¡¶ä¸ï¼ä½¿`rehash`åç`Entry`æ°æ®è·ç¦»æ£ç¡®çæ¡¶çä½ç½®æ´è¿ä¸äºãæä½é»è¾å¦ä¸ï¼

å¦ä¸å¾ï¼`set(27)` ç»è¿hash计ç®ååºè¯¥è½å°`index=4`çæ¡¶ä¸ï¼ç±äº`index=4`æ¡¶å·²ç»æäºæ°æ®ï¼æä»¥å¾åè¿ä»£æç»æ°æ®æ¾å
¥å°`index=7`çæ¡¶ä¸ï¼æ¾å
¥å䏿®µæ¶é´å`index=5`ä¸ç`Entry`æ°æ®`key`å为äº`null`

妿åæå
¶ä»æ°æ®`set`å°`map`ä¸ï¼å°±ä¼è§¦å**æ¢æµå¼æ¸
ç**æä½ã
å¦ä¸å¾ï¼æ§è¡**æ¢æµå¼æ¸
ç**åï¼`index=5`çæ°æ®è¢«æ¸
çæï¼ç»§ç»å¾åè¿ä»£ï¼å°`index=7`çå
ç´ æ¶ï¼ç»è¿`rehash`ååç°è¯¥å
ç´ æ£ç¡®ç`index=4`ï¼èæ¤ä½ç½®å·²ç»å·²ç»æäºæ°æ®ï¼å¾åæ¥æ¾ç¦»`index=4`æè¿ç`Entry=null`çèç¹(åè¢«æ¢æµå¼æ¸
çæçæ°æ®ï¼index=5)ï¼æ¾å°åç§»å¨`index= 7`çæ°æ®å°`index=5`ä¸ï¼æ¤æ¶æ¡¶çä½ç½®ç¦»æ£ç¡®çä½ç½®`index=4`æ´è¿äºã
ç»è¿ä¸è½®æ¢æµå¼æ¸
çåï¼`key`è¿æçæ°æ®ä¼è¢«æ¸
çæï¼æ²¡è¿æçæ°æ®ç»è¿`rehash`éå®ä½åæå¤çæ¡¶ä½ç½®çè®ºä¸æ´æ¥è¿`i= key.hashCode & (tab.len - 1)`çä½ç½®ãè¿ç§ä¼å伿髿´ä¸ªæ£å表æ¥è¯¢æ§è½ã
æ¥ççä¸`expungeStaleEntry()`å
·ä½æµç¨ï¼æä»¬è¿æ¯ä»¥å
åçå¾åæºç è®²è§£çæ¹å¼æ¥ä¸æ¥æ¥æ¢³çï¼

æä»¬å设`expungeStaleEntry(3)` æ¥è°ç¨æ¤æ¹æ³ï¼å¦ä¸å¾æç¤ºï¼æä»¬å¯ä»¥çå°`ThreadLocalMap`ä¸`table`çæ°æ®æ
åµï¼æ¥çæ§è¡æ¸
çæä½ï¼

ç¬¬ä¸æ¥æ¯æ¸
空å½å`staleSlot`ä½ç½®çæ°æ®ï¼`index=3`ä½ç½®ç`Entry`åæäº`null`ãç¶åæ¥çå¾åæ¢æµï¼

æ§è¡å®ç¬¬äºæ¥åï¼index=4çå
ç´ æªå°index=3çæ§½ä½ä¸ã
ç»§ç»å¾åè¿ä»£æ£æ¥ï¼ç¢°å°æ£å¸¸æ°æ®ï¼è®¡ç®è¯¥æ°æ®ä½ç½®æ¯å¦åç§»ï¼å¦æè¢«åç§»ï¼åéæ°è®¡ç®`slot`ä½ç½®ï¼ç®çæ¯è®©æ£å¸¸æ°æ®å°½å¯è½åæ¾å¨æ£ç¡®ä½ç½®æç¦»æ£ç¡®ä½ç½®æ´è¿çä½ç½®

å¨å¾åè¿ä»£çè¿ç¨ä¸ç¢°å°ç©ºçæ§½ä½ï¼ç»æ¢æ¢æµï¼è¿æ ·ä¸è½®æ¢æµå¼æ¸
çå·¥ä½å°±å®æäºï¼æ¥çæä»¬ç»§ç»ççå
·ä½**å®ç°æºä»£ç **ï¼
```java
private int expungeStaleEntry(int staleSlot) {
Entry[] tab = table;
int len = tab.length;
tab[staleSlot].value = null;
tab[staleSlot] = null;
size--;
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;
while (tab[h] != null)
h = nextIndex(h, len);
tab[h] = e;
}
}
}
return i;
}
```
è¿éæä»¬è¿æ¯ä»¥`staleSlot=3` æ¥å示ä¾è¯´æï¼é¦å
æ¯å°`tab[staleSlot]`æ§½ä½çæ°æ®æ¸
空ï¼ç¶å设置`size--`
æ¥ç以`staleSlot`ä½ç½®å¾åè¿ä»£ï¼å¦æéå°`k==null`çè¿ææ°æ®ï¼ä¹æ¯æ¸
ç©ºè¯¥æ§½ä½æ°æ®ï¼ç¶å`size--`
```java
ThreadLocal> k = e.get();
if (k == null) {
e.value = null;
tab[i] = null;
size--;
}
```
妿`key`没æè¿æï¼éæ°è®¡ç®å½å`key`ç䏿 ä½ç½®æ¯ä¸æ¯å½åæ§½ä½ä¸æ ä½ç½®ï¼å¦æä¸æ¯ï¼é£ä¹è¯´æäº§çäº`hash`å²çªï¼æ¤æ¶ä»¥æ°è®¡ç®åºæ¥æ£ç¡®çæ§½ä½ä½ç½®å¾åè¿ä»£ï¼æ¾å°æè¿ä¸ä¸ªå¯ä»¥åæ¾`entry`çä½ç½®ã
```java
int h = k.threadLocalHashCode & (len - 1);
if (h != i) {
tab[i] = null;
while (tab[h] != null)
h = nextIndex(h, len);
tab[h] = e;
}
```
è¿éæ¯å¤çæ£å¸¸ç产ç`Hash`å²çªçæ°æ®ï¼ç»è¿è¿ä»£åï¼æè¿`Hash`å²çªæ°æ®ç`Entry`ä½ç½®ä¼æ´é è¿æ£ç¡®ä½ç½®ï¼è¿æ ·çè¯ï¼æ¥è¯¢çæ¶å æçæä¼æ´é«ã
### `ThreadLocalMap`æ©å®¹æºå¶
å¨``ThreadLocalMap.set()`æ¹æ³çæåï¼å¦ææ§è¡å®å¯å弿¸
çå·¥ä½åï¼æªæ¸
çå°ä»»ä½æ°æ®ï¼ä¸å½åæ£åæ°ç»ä¸`Entry`çæ°éå·²ç»è¾¾å°äºåè¡¨çæ©å®¹éå¼`(len*2/3)`ï¼å°±å¼å§æ§è¡`rehash()`é»è¾ï¼
```java
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
```
æ¥ççä¸`rehash()`å
·ä½å®ç°ï¼
```java
private void rehash() {
expungeStaleEntries();
if (size >= threshold - threshold / 4)
resize();
}
private void expungeStaleEntries() {
Entry[] tab = table;
int len = tab.length;
for (int j = 0; j = threshold - threshold / 4` ä¹å°±æ¯`size >= threshold* 3/4` æ¥å³å®æ¯å¦æ©å®¹ã
æä»¬è¿è®°å¾ä¸é¢è¿è¡`rehash()`çé弿¯`size >= threshold`ï¼æä»¥å½é¢è¯å®å¥è·¯æä»¬`ThreadLocalMap`æ©å®¹æºå¶çæ¶å æä»¬ä¸å®è¦è¯´æ¸
æ¥è¿ä¸¤ä¸ªæ¥éª¤ï¼

æ¥çççå
·ä½ç`resize()`æ¹æ³ï¼ä¸ºäºæ¹ä¾¿æ¼ç¤ºï¼æä»¬ä»¥`oldTab.len=8`æ¥ä¸¾ä¾ï¼

æ©å®¹åç`tab`ç大å°ä¸º`oldLen * 2`ï¼ç¶åéåèçæ£å表ï¼éæ°è®¡ç®`hash`ä½ç½®ï¼ç¶åæ¾å°æ°ç`tab`æ°ç»ä¸ï¼å¦æåºç°`hash`å²çªåå¾åå¯»æ¾æè¿ç`entry`为`null`çæ§½ä½ï¼éå宿ä¹åï¼`oldTab`䏿æç`entry`æ°æ®é½å·²ç»æ¾å
¥å°æ°ç`tab`ä¸äºãéæ°è®¡ç®`tab`䏿¬¡æ©å®¹ç**éå¼**ï¼å
·ä½ä»£ç å¦ä¸ï¼
```java
private void resize() {
Entry[] oldTab = table;
int oldLen = oldTab.length;
int newLen = oldLen * 2;
Entry[] newTab = new Entry[newLen];
int count = 0;
for (int j = 0; j k = e.get();
if (k == null) {
e.value = null;
} 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;
}
```
### `ThreadLocalMap.get()`详解
ä¸é¢å·²ç»çå®äº`set()`æ¹æ³çæºç ï¼å
¶ä¸å
æ¬`set`æ°æ®ãæ¸
çæ°æ®ãä¼åæ°æ®æ¡¶çä½ç½®çæä½ï¼æ¥ççç`get()`æä½çåçã
#### `ThreadLocalMap.get()`å¾è§£
**第ä¸ç§æ
åµï¼** éè¿æ¥æ¾`key`å¼è®¡ç®åºæ£å表ä¸`slot`ä½ç½®ï¼ç¶å该`slot`ä½ç½®ä¸ç`Entry.key`忥æ¾ç`key`ä¸è´ï¼åç´æ¥è¿åï¼

**第äºç§æ
åµï¼** `slot`ä½ç½®ä¸ç`Entry.key`åè¦æ¥æ¾ç`key`ä¸ä¸è´ï¼

æä»¬ä»¥`get(ThreadLocal1)`为ä¾ï¼éè¿`hash`计ç®åï¼æ£ç¡®ç`slot`ä½ç½®åºè¯¥æ¯4ï¼è`index=4`çæ§½ä½å·²ç»æäºæ°æ®ï¼ä¸`key`å¼ä¸çäº``ThreadLocal`1`ï¼æä»¥éè¦ç»§ç»å¾åè¿ä»£æ¥æ¾ã
è¿ä»£å°`index=5`çæ°æ®æ¶ï¼æ¤æ¶`Entry.key=null`ï¼è§¦å䏿¬¡æ¢æµå¼æ°æ®åæ¶æä½ï¼æ§è¡`expungeStaleEntry()`æ¹æ³ï¼æ§è¡å®åï¼`index 5,8`çæ°æ®é½ä¼è¢«åæ¶ï¼è`index 6,7`çæ°æ®é½ä¼åç§»ï¼æ¤æ¶ç»§ç»å¾åè¿ä»£ï¼å°`index = 6`çæ¶å峿¾å°äº`key`å¼ç¸çç`Entry`æ°æ®ï¼å¦ä¸å¾æç¤ºï¼

#### `ThreadLocalMap.get()`æºç 详解
`java.lang.ThreadLocal.ThreadLocalMap.getEntry()`:
```java
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);
}
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)
return e;
if (k == null)
expungeStaleEntry(i);
else
i = nextIndex(i, len);
e = tab[i];
}
return null;
}
```
### `ThreadLocalMap`è¿ækeyçå¯å弿¸
çæµç¨
ä¸é¢å¤æ¬¡æåå°`ThreadLocalMap`è¿æå¯ä»¥çä¸¤ç§æ¸
çæ¹å¼ï¼**æ¢æµå¼æ¸
ç(expungeStaleEntry())**ã**å¯å弿¸
ç(cleanSomeSlots())**
æ¢æµå¼æ¸
çæ¯ä»¥å½å`Entry` å¾åæ¸
çï¼éå°å¼ä¸º`null`åç»ææ¸
çï¼å±äº**çº¿æ§æ¢æµæ¸
ç**ã
èå¯å弿¸
ç被ä½è
å®ä¹ä¸ºï¼**Heuristically scan some cells looking for stale entries**.

å
·ä½ä»£ç å¦ä¸ï¼
```java
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;
}
```
### `InheritableThreadLocal`
æä»¬ä½¿ç¨`ThreadLocal`çæ¶åï¼å¨å¼æ¥åºæ¯ä¸æ¯æ æ³ç»å线ç¨å
±äº«ç¶çº¿ç¨ä¸å建ç线ç¨å¯æ¬æ°æ®çã
为äºè§£å³è¿ä¸ªé®é¢ï¼JDKä¸è¿æä¸ä¸ª`InheritableThreadLocal`ç±»ï¼æä»¬æ¥çä¸ä¸ªä¾åï¼
```java
public class InheritableThreadLocalDemo {
public static void main(String[] args) {
ThreadLocal ThreadLocal = new ThreadLocal();
ThreadLocal inheritableThreadLocal = new InheritableThreadLocal();
ThreadLocal.set("ç¶ç±»æ°æ®:threadLocal");
inheritableThreadLocal.set("ç¶ç±»æ°æ®:inheritableThreadLocal");
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("å线ç¨è·åç¶ç±»`ThreadLocal`æ°æ®ï¼" + `ThreadLocal`.get());
System.out.println("å线ç¨è·åç¶ç±»inheritableThreadLocalæ°æ®ï¼" + inheritableThreadLocal.get());
}
}).start();
}
}
```
æå°ç»æï¼
```java
å线ç¨è·åç¶ç±»`ThreadLocal`æ°æ®ï¼null
å线ç¨è·åç¶ç±»inheritableThreadLocalæ°æ®ï¼ç¶ç±»æ°æ®:inheritableThreadLocal
```
å®ç°åçæ¯åçº¿ç¨æ¯éè¿å¨ç¶çº¿ç¨ä¸éè¿è°ç¨`new Thread()`æ¹æ³æ¥å建å线ç¨ï¼`Thread#init`æ¹æ³å¨`Thread`çæé æ¹æ³ä¸è¢«è°ç¨ãå¨`init`æ¹æ³ä¸æ·è´ç¶çº¿ç¨æ°æ®å°å线ç¨ä¸ï¼
```java
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
if (name == null) {
throw new NullPointerException("name cannot be null");
}
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
this.stackSize = stackSize;
tid = nextThreadID();
}
```
ä½`InheritableThreadLocal`ä»ç¶æç¼ºé·ï¼ä¸è¬æä»¬å弿¥åå¤ç齿¯ä½¿ç¨ççº¿ç¨æ± ï¼è`InheritableThreadLocal`æ¯å¨`new Thread`ä¸ç`init()`æ¹æ³ç»èµå¼çï¼èçº¿ç¨æ± æ¯çº¿ç¨å¤ç¨çé»è¾ï¼æä»¥è¿éä¼åå¨é®é¢ã
å½ç¶ï¼æé®é¢åºç°å°±ä¼æè§£å³é®é¢çæ¹æ¡ï¼é¿é巴巴弿ºäºä¸ä¸ª`TransmittableThreadLocal`ç»ä»¶å°±å¯ä»¥è§£å³è¿ä¸ªé®é¢ï¼è¿éå°±ä¸åå»¶ä¼¸ï¼æå
´è¶£çå¯èªè¡æ¥é
èµæã
### `ThreadLocal`项ç®ä¸ä½¿ç¨å®æ
#### `ThreadLocal`使ç¨åºæ¯
æä»¬ç°å¨é¡¹ç®ä¸æ¥å¿è®°å½ç¨çæ¯`ELK+Logstash`ï¼æåå¨`Kibana`ä¸è¿è¡å±ç¤ºåæ£ç´¢ã
ç°å¨é½æ¯åå¸å¼ç³»ç»ç»ä¸å¯¹å¤æä¾æå¡ï¼é¡¹ç®é´è°ç¨çå
³ç³»å¯ä»¥éè¿traceIdæ¥å
³èï¼ä½æ¯ä¸å项ç®ä¹é´å¦ä½ä¼ é`traceId`å¢ï¼
è¿éæä»¬ä½¿ç¨`org.slf4j.MDC`æ¥å®ç°æ¤åè½ï¼å
é¨å°±æ¯éè¿`ThreadLocal`æ¥å®ç°çï¼å
·ä½å®ç°å¦ä¸ï¼
å½å端åé请æ±å°**æå¡A**æ¶ï¼**æå¡A**ä¼çæä¸ä¸ªç±»ä¼¼`UUID`ç`traceId`å符串ï¼å°æ¤å符串æ¾å
¥å½å线ç¨ç`ThreadLocal`ä¸ï¼å¨è°ç¨**æå¡B**çæ¶åï¼å°`traceId`åå
¥å°è¯·æ±ç`Header`ä¸ï¼**æå¡B**卿¥æ¶è¯·æ±æ¶ä¼å
å¤æè¯·æ±ç`Header`䏿¯å¦æ`traceId`ï¼å¦æåå¨ååå
¥èªå·±çº¿ç¨ç`ThreadLocal`ä¸ã

å¾ä¸ç`requestId`å³ä¸ºæä»¬å个系ç»é¾è·¯å
³èç`traceId`ï¼ç³»ç»é´äºç¸è°ç¨ï¼éè¿è¿ä¸ª`requestId`å³å¯æ¾å°å¯¹åºé¾è·¯ï¼è¿éè¿æä¼æä¸äºå
¶ä»åºæ¯ï¼

é对äºè¿äºåºæ¯ï¼æä»¬é½å¯ä»¥æç¸åºçè§£å³æ¹æ¡ï¼å¦ä¸æç¤º
#### Feignè¿ç¨è°ç¨è§£å³æ¹æ¡
**æå¡åé请æ±ï¼**
```java
@Component
@Slf4j
public class FeignInvokeInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate template) {
String requestId = MDC.get("requestId");
if (StringUtils.isNotBlank(requestId)) {
template.header("requestId", requestId);
}
}
}
```
**æå¡æ¥æ¶è¯·æ±ï¼**
```java
@Slf4j
@Component
public class LogInterceptor extends HandlerInterceptorAdapter {
@Override
public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) {
MDC.remove("requestId");
}
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) {
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String requestId = request.getHeader(BaseConstant.REQUEST_ID_KEY);
if (StringUtils.isBlank(requestId)) {
requestId = UUID.randomUUID().toString().replace("-", "");
}
MDC.put("requestId", requestId);
return true;
}
}
```
#### çº¿ç¨æ± 弿¥è°ç¨ï¼requestIdä¼ é
å 为`MDC`æ¯åºäº`ThreadLocal`å»å®ç°çï¼å¼æ¥è¿ç¨ä¸ï¼å线ç¨å¹¶æ²¡æåæ³è·åå°ç¶çº¿ç¨`ThreadLocal`åå¨çæ°æ®ï¼æä»¥è¿éå¯ä»¥èªå®ä¹çº¿ç¨æ± æ§è¡å¨ï¼ä¿®æ¹å
¶ä¸ç`run()`æ¹æ³ï¼
```java
public class MyThreadPoolTaskExecutor extends ThreadPoolTaskExecutor {
@Override
public void execute(Runnable runnable) {
Map context = MDC.getCopyOfContextMap();
super.execute(() -> run(runnable, context));
}
@Override
private void run(Runnable runnable, Map context) {
if (context != null) {
MDC.setContextMap(context);
}
try {
runnable.run();
} finally {
MDC.remove();
}
}
}
```
#### 使ç¨MQåéæ¶æ¯ç»ç¬¬ä¸æ¹ç³»ç»
å¨MQåéçæ¶æ¯ä½ä¸èªå®ä¹å±æ§`requestId`ï¼æ¥æ¶æ¹æ¶è´¹æ¶æ¯åï¼èªå·±è§£æ`requestId`使ç¨å³å¯ã