ThreadLocal线程内部存储类

63 阅读2分钟

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();

    }
}

打印展示

ThreadLocal的使用

内部数据结构

一个线程类中有一个ThreadLocalMap,ThreadLocalMap中可以有多个Entry,每个Entry都存储了一个ThreadLocal本地变量

set方法源码解析

set方法源码 getMap 创建ThreadLocalMap对象

1.调用时需要传递一个参数
2.进入set方法后,首先获取一个线程对象,使用getMap方法获取当中的ThreadLocalMap对象
3.判断ThreadLocalMap对象是否为空,不为空就用ThreadLocal对象作为Key,值作为Value存储到ThreadLocalMap对象中;为空则直接用当前线程和传递的值创建ThreadLocalMap对象

get方法源码

get方法源码 setInitialValue源码 initialValue源码

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方法进行资源释放