ThreadLocal的使用
代码展示
public class ThreadLocalTest implements Runnable {
private final ThreadLocal<Integer> local = ThreadLocal.withInitial(() -> 0);
private final ThreadLocal<String> stringLocal = new ThreadLocal<>();
public Integer add() {
local.set(local.get() + 1);
return local.get() + 1;
}
public String setStringLocal(String threadName) {
try {
stringLocal.set(threadName);
return stringLocal.get();
} finally {
stringLocal.remove();
}
}
@Override
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println(add() + " --- " + setStringLocal(Thread.currentThread().getName()));
}
}
public static void main(String[] args) {
ThreadLocalTest threadLocalTest = new ThreadLocalTest();
new Thread(threadLocalTest).start();
new Thread(threadLocalTest).start();
}
}
打印展示
内部数据结构
一个线程类中有一个ThreadLocalMap,ThreadLocalMap中可以有多个Entry,每个Entry都存储了一个ThreadLocal本地变量
set方法源码解析
1.调用时需要传递一个参数
2.进入set方法后,首先获取一个线程对象,使用getMap方法获取当中的ThreadLocalMap对象
3.判断ThreadLocalMap对象是否为空,不为空就用ThreadLocal对象作为Key,值作为Value存储到ThreadLocalMap对象中;为空则直接用当前线程和传递的值创建ThreadLocalMap对象
get方法源码
1.进入get方法后,首先同set方法一样获取一个线程对象,使用getMap方法获取当中的ThreadLocalMap对象
2.判断ThreadLocalMap对象是否为空,不为空就用ThreadLocal对象作为键获取Entry对象,然后再判断Entry对象是否为空,不为空就直接获取value值,将其强转成对应数据类型的数据返回;若ThreadLocalMap对象为空,则调用setInitialValue方法返回,setInitialValue方法中首先调用了initialValue方法,initialValue方法中的返回值为null,再回到setInitialValue方法中往下走就同set方法一致了,但走到最后一步会将null返回
可能会导致的内存泄漏
问题原因
1.在ThreadLocal中保存值时,会放入Entry对象
2.Entry是基于弱引用的,若创建的ThreadLocal的线程终止,Entry对象将会被回收
3.但若是创建的ThreadLocal的线程一直持续运行,那当中的value就可能无法回收
解决方法
合理使用ThreadLocal对象,并及时的对其使用remove方法进行资源释放