源码浅析—ThreadLocal

一、ThreadLocal它是什么?有什么作用?

ThreadLocal 是一个存储了线程独有变量的类。

二、它是如何存储线程独有变量的呢?

ThreadLocal 主要是通过自身的一个静态内部类 ThreadLocalMap,对当前线程的变量进行存储的。

首先我们来看一下这个静态内部类

源码浅析—ThreadLocal

那看完了他们的结构关系,我们来看看它是如何 存值 的:ThreadLoacal 中的 set 方法

public void set(T value) {
    Thread t = Thread.currentThread(); // 获取当前线程
    ThreadLocalMap map = getMap(t); // 获取当前线程独有的 ThreadLocalMap
    if (map != null)
        map.set(this, value); // 当前线程对象作为 key,存放键值对
    else
        createMap(t, value); 
}

分析:注意看,里面调用了一个方法: getMap(Thread t),看到这个方法,我们就可以联想到刚刚提到的 ThreadLocalMap,点进去看一下!

ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
}

分析:原来它是返回了传入参数的线程内部的 threadLocals 这个属性,点过去看一下!

源码浅析—ThreadLocal

看到这里,我们就有些明白了。它实际上,是将当前线程对象获取出来,然后把当前线程对象作为key,以 key:value 的形式存入到它的静态内部类中的 Entry 数组中去了。

三、Entry 为什么使用了弱引用呢?

一开始看整体结构的时候,我们就发现了,Entry 数组它继承了 弱引用类,那原因是什么呢?

举个例子:首先在 main 线程中定义一个方法,里面创建一个 ThreadLocal对象,进行存取值

public void func1() {
        ThreadLocal t = new ThreadLocal<Integer>(); 
         t.set(1);   
         t.get();      
}

然后我们观察一下:

源码浅析—ThreadLocal

分析:我们观察可以看见,main 线程的栈中有个栈帧,里面的 ThreadLocal 对象 t 指向了它内部的 ThreadLocal,而 ThreadLocalMap 的 Entry 数组中的 key,也是当前线程对象,也指向了 ThreadLocal。

做一个假设,Entry不使用弱引用:如果方法执行结束,栈帧销毁,那么强引用就没了。但是静态内部类中的成员Entry的引用还在,如果我们不声明为弱引用,那么默认的强引用,将会导致该 ThreadLocal 对象一直不能被回收,将会导致内存泄漏,而弱引用就不同了,一旦栈帧中的对象销毁,该对象只要被GC线程发现,就会被回收了!

参考博客:https://www.cnblogs.com/shen-qian/p/12108655.html

相关推荐