void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue);}
protected T initialValue() { return null; // 初始值是null}
```
从以上这段代码可以看出,ThreadLocal访问的实际上是当前线程的成员变量threadLocals 。<br />threadLocals的数据类型是ThreadLocalMap,这是JDK中专门为ThreadLocal设计的数据结构,它本质就是一个键值对类型 。<br />ThreadLocalMap的键存储的是当前ThreadLocal对象,值是ThreadLocal对象实际存储的值 。<br />当用ThreadLocal对象get方法时 , 它实际上是从当前线程的threadLocals获取键为当前ThreadLocal对象所对应的值 。
画张图来辅助一下理解:<br />![](https://cdn.nlark.com/yuque/0/2022/jpeg/2565452/1667566447745-4dac46dc-c1ad-4a10-b62b-5d9a8506c8fa.jpeg)
清楚了ThreadLocal的get原理,set和remove方法不需要看源码也能猜出是怎么写的 。<br />无非是以ThreadLocal对象为键设置其值或删除键值对 。
# ThreadLocal的初始值
上面的介绍,我们看到ThreadLocal的initialValue方法永远都是返回null的:```javaprotected T initialValue() { return null; // 初始值是null}```
如果想要设定ThreadLocal对象的初始值,可以用以下方法:```javaThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(()->1);System.out.println(threadLocal.get());```withInitial方法内实际返回的是一个ThreadLocal子类SuppliedThreadLocal对象 。<br />SuppliedThreadLocal重写了ThreadLocal的initialValue方法 。```javastatic final class SuppliedThreadLocal<T> extends ThreadLocal<T> {
private final Supplier<? extends T> supplier;
SuppliedThreadLocal(Supplier<? extends T> supplier) { this.supplier = Objects.requireNonNull(supplier); }
@Override protected T initialValue() { return supplier.get(); }}```
# 获取父线程的ThreadLocal变量
在一些场景下,我们可能需要子线程能获取到父线程的ThreadLocal变量,但使用ThreadLocal是无法获取到的:```javapublic static ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
public static void main(String[] args) { threadLocal.set(1); System.out.println(threadLocal.get());
Thread childThread = new Thread(() -> System.out.println(threadLocal.get())); childThread.start();}```输出:```powershell1null```
使用ThreadLocal的子类**InheritableThreadLocal**可以达到这个效果:```javapublic static ThreadLocal<Integer> threadLocal = new InheritableThreadLocal<>();
public static void main(String[] args) { threadLocal.set(1); System.out.println(threadLocal.get());
Thread childThread = new Thread(() -> System.out.println(threadLocal.get())); childThread.start();}``````powershell11```
**InheritableThreadLocal是怎么做到的呢?**
我们来分析一下InheritableThreadLocal的源代码 。```javapublic class InheritableThreadLocal<T> extends ThreadLocal<T> { protected T childValue(T parentValue) { return parentValue; }
ThreadLocalMap getMap(Thread t) { return t.inheritableThreadLocals; }
void createMap(Thread t, T firstValue) { t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue); }}```InheritableThreadLocal的源代码并不多,主要是**覆盖了ThreadLocal的三个方法childValue、getMap、createMap 。**<br />childValue方法用于ThreadLocalMap内部使用 , 我们不打算讲解ThreadLocalMap内部设计,这里可以忽略;<br />ThreadLocal本来getMap、createMap读写的是当前Thread对象的threadLocals变量 。<br />而InheritableThreadLocal将其改为了读写当前Thread对象的InheritableThreadLocal变量 。
接着我们要从Thread类的源码查找头绪 。
Thread类源代码中,我们可以看到有这么2个成员变量:```javaThreadLocal.ThreadLocalMap threadLocals = null;
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;```**如果是使用ThreadLocal创建线程变量,读写的是Thread对象的threadLocals;**<br />**如果是使用InheritableThreadLocal创建线程变量,读写的是Thread对象的inheritableThreadLocals 。**
在Thread类的init方法可以看到(Thread所有构造方法都是调用init方法 , 这边仅贴出关键部分):```javaif (parent.inheritableThreadLocals != null) this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);```ThreadLocal.createInheritedMap:```javastatic ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) { return new ThreadLocalMap(parentMap);}```**如果父级线程的inheritableThreadLocals不为null,那么将父级线程的inheritableThreadLocals赋值到当前线程的inheritableThreadLocals变量 。**
推荐阅读
- 英雄联盟手游战斗之夜活动入口的位置在什么地方
- 原神3.0新增哪些料理
- 原神妮露培养材料需要哪些
- 皮新字组词|皮的新字和组词
- s7vivo参数_s7vivo参数配置
- 樱桃的拼音正确读音-“樱桃”怎么读?
- 浏览器缓存的视频删了怎么恢复(恢复三年内删除的视频)
- 浏览器怎样清除缓存(清理下浏览器的缓存)
- cf怎样跳高箱子(cf高级箱子是怎么跳的)
- cf怎么跳箱子,五种cf跳箱子的方法(cf交易箱子打开不见了)