一、发现问题
使用场景: 拦截器赋值(ThreadLocal.set),不依赖上下文传参,同一个线程内传值(ThreadLocal.get)
使用现象: 在父线程ThreadLocal.set,子线程get不到值。
private final static ThreadLocal<String> threadLocal = new ThreadLocal<>();
public static void main(String[] args) throws InterruptedException {
threadLocal.set("MainSet");
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.submit(() -> {
System.out.println(Thread.currentThread().getName() + " get => " + threadLocal.get());
});
Thread.sleep(1000);
executorService.shutdown();
System.out.println("Main - end");
// out =>
// pool-1-thread-1 get => null
// Main - end
}
二、解决方案
- 传参传进子线程。
- 使用InheritableThreadLocal。
三、ThreadLocal介绍
作用: 线程隔离、线程独享
看源码: threadLocal.set/threadLocal.get

看着像threadLocal1.set、threadLocal2.set
,
实际是Thread.currentThread().ThreadLocalMap.set(ThreadLocal threadLocal1, Object value)、 Thread.currentThread().ThreadLocalMap.set(ThreadLocal threadLocal2, Object value)

实现线程隔离

四、为什么InheritableThreadLocal可以实现子线程传递
看源码...InheritableThreadLocal

由此可见,只是copy,并不共享,copy之后还是隔离
验证....
五、应用场景
- 拦截器,获取上下文。
- PageHelper。
优点: 减少代码侵入
缺点: 不易维护
六、下期讲解
- 内部Map结构、解决hash冲突方式、与jdkHashMap、redis-hash的比较。
- 弱引用、弱引用导致的内存泄漏。
网友评论