一开始啊,我一直没想通,到底 ThreadLocal 这玩意怎么使用。为什么可以防止多线程,我是知道的,我看了它的源码。我也知道是一种泛型的对象,然后每个线程都保留一份。
下面不对源码做过多的介绍,源码详情可参考之前分析的 ThreadLocal:18. 并发容器之ThreadLocal
最近两天,我碰到了一个问题,然后我想到了它可以解决,我思考到了 ThreadLocal 的用途,同时也想通了 InheritableThreadLocal 的用途。
举例说明 ThreadLocal 用途
1 | ThreadLocal<T> 的作用:每个线程都持有一个 T 类型的变量(准确来说是每个线程都有一个 T 类型的对象,这个是线程间私有的。) |
ThreadLocal 实际场景举例
一般来说,在用户登录请求的上下文中会设置一个 “用户id”。
1 | web(request) -> 拦截器(ThreadLocal set 用户id) -> Controller(a-z方法 都可以 get() 获取 “用户id”) |
InheritableThreadLocal 使用场景举例
先说一个这个玩意是什么。它继承了 ThreadLocal。看下面红线,可以知道,它支持线程的值继承。
1 | // 2022-01-10 14:41 ThreadLocal、InheritableThreadLocal 对比测试 |
好了,我就不多说了,你们自己看。红色打印 ‘null’,绿色则打印 ‘I’m InheritableThreadLocal.’。
使用场景
如果使用 InheritableThreadLocal ,子线程1,2,3 默认都继承自主线程中的所有 ThreadLocal 值。
1 | 主线程 a -> b -> c |
原理:
initialValue、childValue
2022-01-26 08:17:34 补充
initialValue():ThreadLocal 类型可用(ThreadLocal、InheritableThreadLocal 两种类型都支持)。
含义:在没有 set 的时候,直接进行 get 讲道理会取出来 null。
但如果为 null 的情况下,会调用 initialValue() 方法的返回值,做为 get获取的值(并会放入 map中)。childValue(T parentValue):InheritableThreadLocal 才可用(仅支持类型 InheritableThreadLocal)。
含义:在创建 Thread 对象的时候,会 copy 父线程的 InheritableThreadLocal。如果 key 存在,调用 childValue方法。
必要时要实现一下深克隆,因为多线程可能造成对象的修改的情况,避免造成脏数据。
总结
1、ThreadLocal 主要应用与线程上下文,不用放在对象中,不用进行方法传参,只有是同一个线程,都可以随时 get() 获取这个变量。
2、InheritableThreadLocal 主要应用与开辟子线程的情况下,让此变量也存在于各个子线程的上下文中。