ThreadLocal
1.线程隔离
//常用操作
static ThreadLocal<threadLocaltlTest> myThreadLocal= new ThreadLocal<>();
myThreadLocal.set(new threadLocaltlTest());
myThreadLocal.get();
/**
* Sets the current thread's copy of this thread-local variable
* to the specified value. Most subclasses will have no need to
* override this method, relying solely on the {@link #initialValue}
* method to set the values of thread-locals.
*
* @param value the value to be stored in the current thread's copy of
* this thread-local.
*/
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
其中 ThreadLocalMap map = getMap(t);获取的是t线程的成员变量threadLocals:
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
每次执行
myThreadLocal.set(new threadLocaltlTest());
时都是向每个线程各自独立的成员变量ThreadLocal.ThreadLocalMap threadLocals中填充数据,从而实现线程隔离。
2.内存泄露
情况1:
map.set(this.value)方法的核心是
/**
* 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;
}
}
map中每个entry对象的key都是通过弱引用指向传入的实例化的ThreadLocal对象
使用弱引用的原因:
如果是使用强引用,则当myThreadLocal = null时,map中还有强引用指向原来myThreadLocal 指向的那个ThreadLocal对象,那么ThreadLocal对象则无法被gc回收,造成内存泄露。
如果是使用弱引用,则当myThreadLocal = null时,map中指向原来myThreadLocal 指向的哪个ThreadLocal对象的引用是弱引用,那么gc执行时ThreadLocal对象就会被清理。
情况2:
当myThreadLocal = null时,通过gc,使得map中的key也是null,那么就无法通过key得到value,需要对该entry进行remove操作,如果不能及时的对该entry进行remove就会造成内存泄露。