[ThreadLocalé æOOMå
åæº¢åºæ¡ä¾æ¼ç¤ºä¸åçåæ](https://blog.csdn.net/xlgen157387/article/details/78298840)
[æ·±å
¥çè§£ Java ä¹ ThreadLocal å·¥ä½åç]()
## ThreadLocal
### ThreadLocalç®ä»
é常æ
åµä¸ï¼æä»¬å建çå鿝å¯ä»¥è¢«ä»»ä½ä¸ä¸ªçº¿ç¨è®¿é®å¹¶ä¿®æ¹çã**妿æ³å®ç°æ¯ä¸ä¸ªçº¿ç¨é½æèªå·±çä¸å±æ¬å°åé该å¦ä½è§£å³å¢ï¼** JDK䏿ä¾ç`ThreadLocal`ç±»æ£æ¯ä¸ºäºè§£å³è¿æ ·çé®é¢ã **`ThreadLocal`类主è¦è§£å³çå°±æ¯è®©æ¯ä¸ªçº¿ç¨ç»å®èªå·±çå¼ï¼å¯ä»¥å°`ThreadLocal`ç±»å½¢è±¡çæ¯å»æåæ¾æ°æ®ççåï¼çåä¸å¯ä»¥å卿¯ä¸ªçº¿ç¨çç§ææ°æ®ã**
**å¦æä½ å建äºä¸ä¸ª`ThreadLocal`åéï¼é£ä¹è®¿é®è¿ä¸ªåéçæ¯ä¸ªçº¿ç¨é½ä¼æè¿ä¸ªåéçæ¬å°å¯æ¬ï¼è¿ä¹æ¯`ThreadLocal`åéåçç±æ¥ãä»ä»¬å¯ä»¥ä½¿ç¨ `getï¼ï¼` å `setï¼ï¼` æ¹æ³æ¥è·åé»è®¤å¼æå°å
¶å¼æ´æ¹ä¸ºå½åçº¿ç¨æåç坿¬çå¼ï¼ä»èé¿å
äºçº¿ç¨å®å
¨é®é¢ã**
å举个ç®åçä¾åï¼
æ¯å¦æä¸¤ä¸ªäººå»å®å±æ¶éå®ç©ï¼è¿ä¸¤ä¸ªå
±ç¨ä¸ä¸ªè¢åçè¯è¯å®ä¼äº§çäºæ§ï¼ä½æ¯ç»ä»ä»¬ä¸¤ä¸ªäººæ¯ä¸ªäººåé
ä¸ä¸ªè¢åçè¯å°±ä¸ä¼åºç°è¿æ ·çé®é¢ã妿æè¿ä¸¤ä¸ªäººæ¯ä½çº¿ç¨çè¯ï¼é£ä¹ThreadLocalå°±æ¯ç¨æ¥è¿ä¸¤ä¸ªçº¿ç¨ç«äºçã
### ThreadLocal示ä¾
ç¸ä¿¡çäºä¸é¢çè§£éï¼å¤§å®¶å·²ç»ææ ThreadLocal ç±»æ¯ä¸ªä»ä¹ä¸è¥¿äºã
```java
import java.text.SimpleDateFormat;
import java.util.Random;
public class ThreadLocalExample implements Runnable{
// SimpleDateFormat 䏿¯çº¿ç¨å®å
¨çï¼æä»¥æ¯ä¸ªçº¿ç¨é½è¦æèªå·±ç¬ç«ç坿¬
private static final ThreadLocal formatter = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyyMMdd HHmm"));
public static void main(String[] args) throws InterruptedException {
ThreadLocalExample obj = new ThreadLocalExample();
for(int i=0 ; i<10; i++){
Thread t = new Thread(obj, ""+i);
Thread.sleep(new Random().nextInt(1000));
t.start();
}
}
@Override
public void run() {
System.out.println("Thread Name= "+Thread.currentThread().getName()+" default Formatter = "+formatter.get().toPattern());
try {
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
//formatter pattern is changed here by thread, but it won't reflect to other threads
formatter.set(new SimpleDateFormat());
System.out.println("Thread Name= "+Thread.currentThread().getName()+" formatter = "+formatter.get().toPattern());
}
}
```
Output:
```
Thread Name= 0 default Formatter = yyyyMMdd HHmm
Thread Name= 0 formatter = yy-M-d ah:mm
Thread Name= 1 default Formatter = yyyyMMdd HHmm
Thread Name= 2 default Formatter = yyyyMMdd HHmm
Thread Name= 1 formatter = yy-M-d ah:mm
Thread Name= 3 default Formatter = yyyyMMdd HHmm
Thread Name= 2 formatter = yy-M-d ah:mm
Thread Name= 4 default Formatter = yyyyMMdd HHmm
Thread Name= 3 formatter = yy-M-d ah:mm
Thread Name= 4 formatter = yy-M-d ah:mm
Thread Name= 5 default Formatter = yyyyMMdd HHmm
Thread Name= 5 formatter = yy-M-d ah:mm
Thread Name= 6 default Formatter = yyyyMMdd HHmm
Thread Name= 6 formatter = yy-M-d ah:mm
Thread Name= 7 default Formatter = yyyyMMdd HHmm
Thread Name= 7 formatter = yy-M-d ah:mm
Thread Name= 8 default Formatter = yyyyMMdd HHmm
Thread Name= 9 default Formatter = yyyyMMdd HHmm
Thread Name= 8 formatter = yy-M-d ah:mm
Thread Name= 9 formatter = yy-M-d ah:mm
```
ä»è¾åºä¸å¯ä»¥çåºï¼Thread-0å·²ç»æ¹åäºformatterçå¼ï¼ä½ä»ç¶æ¯thread-2é»è®¤æ ¼å¼åç¨åºä¸åå§åå¼ç¸åï¼å
¶ä»çº¿ç¨ä¹ä¸æ ·ã
ä¸é¢æä¸æ®µä»£ç ç¨å°äºå建 `ThreadLocal` åéç飿®µä»£ç ç¨å°äº Java8 çç¥è¯ï¼å®çäºä¸é¢è¿æ®µä»£ç ï¼å¦æä½ åäºä¸é¢è¿æ®µä»£ç çè¯ï¼IDEAä¼æç¤ºä½ è½¬æ¢ä¸ºJava8çæ ¼å¼(IDEAççä¸éï¼)ãå 为ThreadLocalç±»å¨Java 8䏿©å±ï¼ä½¿ç¨ä¸ä¸ªæ°çæ¹æ³`withInitial()`ï¼å°Supplieråè½æ¥å£ä½ä¸ºåæ°ã
```java
private static final ThreadLocal formatter = new ThreadLocal(){
@Override
protected SimpleDateFormat initialValue()
{
return new SimpleDateFormat("yyyyMMdd HHmm");
}
};
```
### ThreadLocalåç
ä» `Thread`ç±»æºä»£ç å
¥æã
```java
public class Thread implements Runnable {
......
//䏿¤çº¿ç¨æå
³çThreadLocalå¼ãç±ThreadLocal类维æ¤
ThreadLocal.ThreadLocalMap threadLocals = null;
//䏿¤çº¿ç¨æå
³çInheritableThreadLocalå¼ãç±InheritableThreadLocal类维æ¤
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
......
}
```
ä»ä¸é¢`Thread`ç±» æºä»£ç å¯ä»¥çåº`Thread` ç±»ä¸æä¸ä¸ª `threadLocals` å ä¸ä¸ª `inheritableThreadLocals` åéï¼å®ä»¬é½æ¯ `ThreadLocalMap` ç±»åçåé,æä»¬å¯ä»¥æ `ThreadLocalMap` ç解为`ThreadLocal` ç±»å®ç°çå®å¶åç `HashMap`ãé»è®¤æ
åµä¸è¿ä¸¤ä¸ªåé齿¯nullï¼åªæå½å线ç¨è°ç¨ `ThreadLocal` ç±»ç `set`æ`get`æ¹æ³æ¶æå建å®ä»¬ï¼å®é
ä¸è°ç¨è¿ä¸¤ä¸ªæ¹æ³çæ¶åï¼æä»¬è°ç¨çæ¯`ThreadLocalMap`类对åºç `get()`ã`set() `æ¹æ³ã
`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);
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
```
éè¿ä¸é¢è¿äºå
å®¹ï¼æä»¬è¶³ä»¥éè¿çæµå¾åºç»è®ºï¼**æç»çå鿝æ¾å¨äºå½å线ç¨ç `ThreadLocalMap` ä¸ï¼å¹¶ä¸æ¯åå¨ `ThreadLocal` ä¸ï¼ThreadLocal å¯ä»¥çè§£ä¸ºåªæ¯ThreadLocalMapçå°è£
ï¼ä¼ éäºåéå¼ã**
**æ¯ä¸ªThreadä¸é½å
·å¤ä¸ä¸ªThreadLocalMapï¼èThreadLocalMapå¯ä»¥åå¨ä»¥ThreadLocal为keyçé®å¼å¯¹ã** æ¯å¦æä»¬å¨åä¸ä¸ªçº¿ç¨ä¸å£°æäºä¸¤ä¸ª `ThreadLocal` 对象çè¯ï¼ä¼ä½¿ç¨ `Thread`å
é¨é½æ¯ä½¿ç¨ä»
æé£ä¸ª`ThreadLocalMap` åæ¾æ°æ®çï¼`ThreadLocalMap`ç key å°±æ¯ `ThreadLocal`对象ï¼value å°±æ¯ `ThreadLocal` 对象è°ç¨`set`æ¹æ³è®¾ç½®çå¼ã`ThreadLocal` æ¯ mapç»ææ¯ä¸ºäºè®©æ¯ä¸ªçº¿ç¨å¯ä»¥å
³èå¤ä¸ª `ThreadLocal`åéãè¿ä¹å°±è§£éäºThreadLocal声æçåé为ä»ä¹å¨æ¯ä¸ä¸ªçº¿ç¨é½æèªå·±çä¸å±æ¬å°åéã
```java
public class Thread implements Runnable {
......
//䏿¤çº¿ç¨æå
³çThreadLocalå¼ãç±ThreadLocal类维æ¤
ThreadLocal.ThreadLocalMap threadLocals = null;
//䏿¤çº¿ç¨æå
³çInheritableThreadLocalå¼ãç±InheritableThreadLocal类维æ¤
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
......
}
```
`ThreadLocalMap`æ¯`ThreadLocal`çéæå
é¨ç±»ã

### ThreadLocal å
åæ³é²é®é¢
`ThreadLocalMap` ä¸ä½¿ç¨ç key 为 `ThreadLocal` çå¼±å¼ç¨,è value æ¯å¼ºå¼ç¨ãæä»¥ï¼å¦æ `ThreadLocal` 没æè¢«å¤é¨å¼ºå¼ç¨çæ
åµä¸ï¼å¨åå¾åæ¶çæ¶åä¼ key ä¼è¢«æ¸
çæï¼è value ä¸ä¼è¢«æ¸
çæãè¿æ ·ä¸æ¥ï¼`ThreadLocalMap` ä¸å°±ä¼åºç°key为nullçEntryãå妿们ä¸å任使ªæ½çè¯ï¼value æ°¸è¿æ æ³è¢«GC åæ¶ï¼è¿ä¸ªæ¶åå°±å¯è½ä¼äº§çå
åæ³é²ãThreadLocalMapå®ç°ä¸å·²ç»èèäºè¿ç§æ
åµï¼å¨è°ç¨ `set()`ã`get()`ã`remove()` æ¹æ³çæ¶åï¼ä¼æ¸
çæ key 为 null çè®°å½ã使ç¨å® `ThreadLocal`æ¹æ³å æå¥½æå¨è°ç¨`remove()`æ¹æ³
```java
static class Entry extends WeakReference> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal> k, Object v) {
super(k);
value = v;
}
}
```
**å¼±å¼ç¨ä»ç»ï¼**
> 妿ä¸ä¸ªå¯¹è±¡åªå
·æå¼±å¼ç¨ï¼é£å°±ç±»ä¼¼äº**坿坿 ççæ´»ç¨å**ãå¼±å¼ç¨ä¸è½¯å¼ç¨çåºå«å¨äºï¼åªå
·æå¼±å¼ç¨çå¯¹è±¡æ¥ææ´çæççå½å¨æãå¨åå¾åæ¶å¨çº¿ç¨æ«æå® æç®¡è¾çå
ååºåçè¿ç¨ä¸ï¼ä¸æ¦åç°äºåªå
·æå¼±å¼ç¨ç对象ï¼ä¸ç®¡å½åå
å空é´è¶³å¤ä¸å¦ï¼é½ä¼åæ¶å®çå
åãä¸è¿ï¼ç±äºåå¾åæ¶å¨æ¯ä¸ä¸ªä¼å
级å¾ä½ç线ç¨ï¼ å æ¤ä¸ä¸å®ä¼å¾å¿«åç°é£äºåªå
·æå¼±å¼ç¨ç对象ã
>
> å¼±å¼ç¨å¯ä»¥åä¸ä¸ªå¼ç¨éåï¼ReferenceQueueï¼èå使ç¨ï¼å¦æå¼±å¼ç¨æå¼ç¨ç对象被åå¾åæ¶ï¼Javaèææºå°±ä¼æè¿ä¸ªå¼±å¼ç¨å å
¥å°ä¸ä¹å
³èçå¼ç¨éåä¸ã