ThreadLocal 使用场景
-
每个线程都需要一个独享的对象(一般用于工具类) 这样做的目的是防止创建过多对象
-
用于多个线程的都需要保存的全局变量
- 解决多层方法调用直接的方法传递问题 如果 设置语言环境 这样就不需要把参数从 controller->service->dao 层层传递下来
- 例如 日志初始化日志 tag需要在任意输出日志时需要缓存对应信息
ThreadLocal原理
Thread ThreadLocal ThreadLocalMap 关系
ThreadLocal重要方法
- void initialValue() 延迟加载 初始赋值, 客户端如果没有使用就get 会调用initialValue
- T get()
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
//
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
- void set()
- void remove()
ThreadLocal使用需要注意点
使用ThreadLocal 可能导致导致内存泄漏问题
ThreadLocal 可能导致导致内存泄漏问题原因
ThreadLocalMap设计 key 为ThreadLocal且会弱引用 value 是强引用对象
如果 线程不终止 则Thread-> ThreadLocalMap-> Entry-> value 生命周期等同线程的生命周期
Entry的key 是弱引用可以被GC回收,因value为强引用导致key为null时 无法被使用则发生内存泄漏 Thead->ThreadLocalMap->Entry( (key弱引用,value))->value
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}`
ThreadLocalMap为防止内存泄漏做出的设计
set ,remove,rehash 会扫描key为null 的entry 并会把对应value设置为null
ThreadLocal使用NPE问题
ThreadLocal 赋值后,如果新开线程之间get 则会导致NPE问题 主要get方法对应基本类型拆箱问题
ThreadLocal,InheritableThreadLocal,TransmittableThreadLocal
ThreadLocal缺陷
如果新开一个子线程 则无法传递给子线程,可以使用解决 InheritableThreadLocal
InheritableThreadLocal缺陷
如果存在线程复用情况,InheritableThreadLocal则会出现问题需要使用TransmittableThreadLocal