共计 739 个字符,预计需要花费 2 分钟才能阅读完成。
Thread 有一个 ThreadLocal.ThreadLocalMap 类型的 threadLocals 成员变量,他是一个 map,底层是一个 ThreadLocalMap.Entry 的数组,每个 ThreadLocal 变量都有一个 threadLocalHashCode,根据这个 hashcode 可计算出当前 ThreadLocal 在数组的 index 值。ThreadLocalMap.Entry 是一个弱引用类型 WeakReference<ThreadLocal<?>>,Entry 的 value 就是我们需要存储的对象,而 key 则是一个弱引用的 referent,当 ThreadLocal 没有任何强引用时,GC 后即使还有弱应用存在也会被回收,这时 Entry 的 key 为 null。所以即使线程一直活着,只要 ThreadLocal 不存在任何强引用,就会被回收器回收,避免内存泄漏。
那么问题来了,即使 Entry 的 key 为弱引用会被回收,但 value 一直以 key 为 null 的 Entry 保存在 map 中,这是强引用,永远不会被回收。ThreadLocalMap 的解决方法是在每次 get、set、remove 时都会将 key 为 null 的 entry 清除掉,这样就会被垃圾回收器清理了。
为什么不将 entry 的 value 也设置为弱引用呢,这是因为如果 value 是弱引用,执行 GC 后,若 value 被清除,那我们永远也拿不到 ThreadLocal 保存的数据了。
通常实践中,我们常把 ThreadLocal 做为单例使用,因为我们要保证 key 为 ThreadLocal 的值全局都能访问到。当不是单例使用情况下,我们要记得在不实用 ThreadLocal 时调用一下 ThreadLocal.remove() 方法,删除 key。help gc.