ThreadLocal
多线程中对于解决线程安全的一个操作类
为每个线程都分配一个独立的ThreadLocal对象副本
实现了线程间的数据隔离
//创建ThreadLocal对象,定义对象内资源的类型
ThreadLocal<String> tl = new ThreadLocal<>();set()//向对象中存入值,每个线程独立
get()//获取对象中的值,每个线程独立
remove()//清除
ThreadLocal实现原理
Thread类
thread类中维护了一个ThreadLocal的内部类ThreadLocalMap对象
ThreadLocalMap对象中维护了一个Entry数组
即每个线程中都维护了一个独立的Entry数组
我们将线程间独立的数据存储在这个Entry数组中
以ThreadLocal对象作为key,value作为值
这样就实现了同一个ThreadLocal对象的数据隔离
ThreadLocal.ThreadLocalMap threadLocals = null;
Set
public void set(T value) {//获取当前的线程对象Thread t = Thread.currentThread();//根据线程对象获取对应的mapThreadLocalMap map = getMap(t);if (map != null) {map.set(this, value);} else {createMap(t, value);}}
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();}
ThreadLocal的内存泄漏问题
因为ThreadLocalMap中的key是ThreadLocal的弱引用
static class ThreadLocalMap {/*** The entries in this hash map extend WeakReference, using* its main ref field as the key (which is always a* ThreadLocal object). Note that null keys (i.e. entry.get()* == null) mean that the key is no longer referenced, so the* entry can be expunged from table. Such entries are referred to* as "stale entries" in the code that follows.*/static class Entry extends WeakReference<ThreadLocal<?>> {/** The value associated with this ThreadLocal. */Object value;Entry(ThreadLocal<?> k, Object v) {super(k);value = v;}}
}
所以当ThreadLocal对象没有任何的强引用时
(ThreadLocal变量被手动置为空)
,就会在下一次GC时被手动回收
就导致ThreadLocalMap中出现了一个key为null的Entry
无法访问对应的value,同时Entry又不会被GC回收
导致内存泄漏
内存泄漏:
资源不会被程序用到,同时也无法被GC回收
为什么不使用强引用
强引用会导致ThreadLocal对象被回收时,key不会被回收,出现内存泄漏问题
而弱引用虽然也会导致内存泄漏,但可以在下一次set/get/remove时检查nullkey进行清除