直接先線程池中獲取主線程或非線程池中的ThreadLocal設置的變量的值
例如
private static final ThreadPoolExecutor syncAccessPool = new ThreadPoolExecutor(
50,
80,
8000,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(600)
);
public static void main(String[] args) {
ThreadLocal<String> threadLocal = new ThreadLocal<>();
threadLocal.set("userId115807");
syncAccessPool.execute(()->{
System.out.println(threadLocal.get());
});
}
最後打印的結果是null
解決辦法:真實使用中相信大家不會這麼使用的,但是我出錯主要是因爲使用了封裝的方法,封裝的方法中使用了ThreadLocal,這種情況下要先從ThreadLocal中獲取到方法中,再設置到線程池
線程池中使用了ThreadLocal設置了值但是使用完後並未移除造成內存飆升或OOM
public class ThreadLocalOOM {
static class LocalVariable{
private Long[] a = new Long[1024*1024];
}
private static final ThreadPoolExecutor syncAccessPool = new ThreadPoolExecutor(
50,
80,
8000,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(600)
);
final static ThreadLocal<LocalVariable> threadLocal = new ThreadLocal<LocalVariable>();
public static void main(String[] args) throws InterruptedException {
Thread.sleep(10000);
for (int i=0;i<100;i++){
syncAccessPool.execute(()->{
threadLocal.set(new LocalVariable());
System.out.println("use local variable");
});
Thread.sleep(1000);
}
System.out.println("pool execute over");
}
}
這個程序使用jconsole程序觀察到的內存變化爲
在使用完之後remove之後的內存變化
public static void main(String[] args) throws InterruptedException {
for (int i=0;i<100;i++){
syncAccessPool.execute(()->{
threadLocal.set(new LocalVariable());
System.out.println("use local variable");
threadLocal.remove();
});
Thread.sleep(1000);
}
System.out.println("pool execute over");
}
內存相比之前降低了幾倍。這個原因就是沒有remove,線程池中所有存在的線程都會持有這個本地變量,導致內存暴漲。如果將private Long[] a = new Long[1024*1024]; 擴大可能就會很快拋出OOM異常