1.ThreadLocal 简介
ThreadLocal为 多线程同步机制的 提供了解决思路,每个线程都可以去改变自己的变量副本,他们之间相互隔离,互不影响
2.ThreadLocal 的作用
让线程保存一份自己的变量副本,每个线程都独立使用自己的变量副本,这样就不会影响其他的线程
3.ThreadLocal 的内部机制 内部数据结构
维护了一个 ThreadLocalMap
由key-value 组成的entry 数组
key 是threadlocal 的 弱引用
value 对象线程变量的副本
4.ThreadLocal 的相关源码分析
4.1 删除方法
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
4.2 获取方法
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();
}
4.3 创建方法
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
5.ThreadLocal 在项目中的应用
5.1.session 是线程不安全的,因此在多线程环境下,session 不能为共享对象
5.2 每次运行都要打开以及关闭session 对象 导致性能受影响
综合以上以上因素,使用了ThreadLocal
private static final ThreadLocal<Map<String, Object>> SESSION_LOCAL = new ThreadLocal<>();
/**
* makeThreadValue
*
* @param key
* @param value
*/
public static <T> void makeThreadValue(String key, T value) {
Map<String, Object> context = SESSION_LOCAL.get();
if (context == null) {
context = new ConcurrentHashMap<>();
SESSION_LOCAL.set(context);
}
if (key != null && value != null) {
context.put(key, value);
}
}
6.内存泄露问题
上图中,实线代表强引用,虚线代表的是弱引用,如果threadLocal外部强引用被置为null(threadLocalInstance=null)的话,threadLocal实例就没有一条引用链路可达,很显然在gc(垃圾回收)的时候势必会被回收,因此entry就存在key为null的情况,无法通过一个Key为null去访问到该entry的value。同时,就存在了这样一条引用链:threadRef->currentThread->threadLocalMap->entry->valueRef->valueMemory,导致在垃圾回收的时候进行可达性分析的时候,value可达从而不会被回收掉,但是该value永远不能被访问到,这样就存在了内存泄漏。