深入学习ThreadLocal
1、用来干吗的?
用于线程在任意的地方去共享数据,而不被其他线程所干扰,
2、原理是什么
因为每个线程维护一份ThreadLocalMap,使用threadlocal.set(obj)方法是存放在map里面的Entry<<WeekReference>ThreadLocal,Value>数组里
3、实际案例,比如写了util类,但是SimplateDateFormate是线程不安全的,定义成成员变量多线程调用就会有问题,使用threadlocal相当于每个线程都有一份这个value,也就是simplateDateFormate对象


4、为什么不使用thread的id作为Entry的key
当有两个ThreaLocal1和ThreadLocal2时候,在local1设置的值会被loca2中读到,但使用Threadlocal作为key就能区分
5、key为什么会设置弱引用,为什么会内存泄漏
当手动回收了ThreadLocal对象,如果是强引用,那么Entry还有一个对ThreadLocal的强引用,如果不手动删除,会导致这个Entry一直存在
从而导致内存泄漏,当使用弱引用,回收了ThreadLocal对象后,Entry里面是个弱引用,ThreadLocal就会被回收,Entry面的key变成null
在下一次get set remove就会清除掉这些key为null的数据 ,相当于提供了一层保障。
6、使用注意点
使用static修饰threadlocal修饰,当get完调用一次remove清除当此的Entry.
附上一个线程泄漏导致oom的例子
VM参数 -Xms5m -Xmx5m -XX:+HeapDumpOnOutOfMemoryError
package com.xiangwen.day10;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadLocalTest2 {
private static ThreadLocal<MyThreadLocal> threadLocal = new ThreadLocal<>();
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 0, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(1000));
for (int i = 0; i < 10; i++) {
executor.execute(new Runnable() {
@Override
public void run() {
long time= Math.round(Math.random()*2000);
try {
Thread.sleep(time);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName() +
"休眠结束"+time);
MyThreadLocal myThreadLocal = new MyThreadLocal();
threadLocal.set(myThreadLocal);
// System.gc();
//threadLocal.remove();
}
});
}
}
static class MyThreadLocal {
private byte[] bytes = new byte[1 * 1024 * 1024];
}
}

浙公网安备 33010602011771号