您的位置:首页 > 其它

ThreadLocal的解析

2018-03-28 17:32 330 查看

ThreadLocal的使用

是线程私有的,那么必然是线程安全的,使用ThreadLocal实现线程本地存储的功能,也就是说我有个变量需要被一个线程独享,并且可以随时取用,那么ThreadLocal是一个很好的选择,比如在web开发中使用ThreadLocal存储User信息,方便随时调用,线程内部随时可以调用,相当于车子后面的后备箱。

看看ThreadLocal的源码:

public void set(T value) {
//取得当前线程对应的map
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
//如果map != null this为key
if (map != null)
map.set(this, value);
else
/**否则
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
} */
createMap(t, value);
}

public T get() {
//首先取得当前线程
Thread t = Thread.currentThread();
//Thread类定义了一个map,ThreadLocal.ThreadLocalMap threadLocals = null;
//thread上面挂了一个map,取得这个map
ThreadLocalMap map = getMap(t);
if (map != null) {
//如果map != null ,取出this对应的entry
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
//取出存储数据
return result;
}
}
return setInitialValue();
}

####ThreadLocal如何退出呢?
了解ThreadLocal的内部实现后,ThreadLocal是Thread类内部定义的,也就意味着ThreadLocal的生命周期和线程是相同的,线程不退出,那么ThreadLocal就无法被回收。
> - 线程退出的时候:


ThreadLocal如何退出呢?

了解ThreadLocal的内部实现后,ThreadLocal是Thread类内部定义的,也就意味着ThreadLocal的生命周期和线程是相同的,线程不退出,那么ThreadLocal就无法被回收。

线程退出的时候:

private void exit() {
if (group != null) {
group.threadTerminated(this);
group = null;
}
/* Aggressively null out all reference fields: see bug 4006245 */
target = null;
/* Speed the release of some of these resources */
threadLocals = null;
//这个地方为什么可以释放ThreadLocal资源,比较它存放在map里面,为什么可以像普通资源一样被释放?弱引用。
inheritableThreadLocals = null;
inheritedAccessControlContext = null;
blocker = null;
uncaughtExceptionHandler = null;
}


ThreadLocalMap使用了弱引用,也就是在map中存储的key不是直接持有引用,所以一旦外部直接引用被置为null,key会变成null,那么map中的value就会被GC回收。

static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;

Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}


那么如果线程不关闭呢?比如线程池,如果线程一直没有exit,那么不同的对象调用,每个都会在ThreadLocalMap中维持一个entry,那么多来几次,可能会出现内存泄漏,那么如何处理?ThreadLocal.remove()方法可以实现这一点。

/**
* Remove the entry for key.
*/
private void remove(ThreadLocal<?> key) {
Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len-1);
for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) {
if (e.get() == key) {
e.clear();
expungeStaleEntry(i);
return;
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息