源码理解ThreadLocal

目录

源码解析:

 一、new ThreadLocal

二、set函数

三、get函数


首先说一下使用方法。

1、创建ThreadLocal 对象 threadLocal。

2、创建线程 A 、线程 B。

3、在线程 A 和线程 B中 调用 threadLocal.set()   get() 函数

常见疑惑:

内存 堆里面只有一个 ThreadLocal,那么一般理解上,线程 A 对 threadLocal 执行 set(value),那么 线程 B 对 threadLocal 执行get 也应该得到 这个value

 代码如下:

执行结果如下:

在不同线程中,对同一个对象执行set get方法,结果不同。


源码解析:

简单总结:

线程持有 ThreadLocalMap对象 -- ThreadLocalMap对象内维持一个数组 --- 数组内对象为 Entry --- Entry继承软引用,Key是软引用 --- Entry的key值是 ThreadLocal对象,Value值是 threadLocal.set(Value) 传递的值

一、new ThreadLocal

1、默认构造器是空实现;

2、默认实例变量没有特殊设置;

二、第一次调用set函数

1、切换到当前线程,这一步很重要。

2、获取当前线程实例变量,threadLocalMap;

3、我们进入到 Thread类中,去看一下 threadLocals

整个 Thread类中,只有这一步用到这个对象。默认为空。

4、那么当我们第一次调用函数 set()的时候,map == null;

5、

6、分析 createMap();

这里的this 是 ThreadLocal对象。

这里我们可以看到,给当前线程的实例变量 threadLocals赋值。

7、分析 new ThreadLocalMap

看一下 new Entry

k值作为软引用。

看一下扩容

总结:当第一次调用 set函数时候,动作如下

切换当前线程 --- 获取当前线程 ThreadLocalMap对象 --- 为空的话,先创建ThreadLocalMap对象 --- ThreadLocalMap对象内部维持了一个Entry数组,数组长度默认16,扩容因子 2/3--- threadLocal对象的hashcode 和 15进行与运算 --- new Entry放置到 数组里面。

Entry 的K是软引用。即 ThreadLocal对象可以随时被内存回收。这一条很重要。

三 、第二次调用set();

第二次调用时,线程的实例变量  threadLocals “其类型是ThreadLocalMap”,不为空。

set这里有些复杂,先简单说。

一般流程是黄色部分。

①:通过hashcode 和 tab.len - 1 做与运算,计算出当前Key应该在tab的哪个位置。

②:判断 i 位置 Entry是否为null;i 的计算方式如下

③:不为null,判断key,如果同一 key 则替换 value

④:如果 i 位置 Entry 为null,则新建 Entry,指向 tab[i]

⑤:cleanSomeSlots 判断是否有 key被回收了

 


最难的部分:

留个坑,下班了