前沿
可先参考之前写的 https://www.yuque.com/u1687194/hspkbf/uvaeep
概览
代码
源码
class Thread {//内部持有ThreadLocalMapThreadLocal.ThreadLocalMap threadLocals;}class ThreadLocal<T> {public T get() {//首先获取线程持有的//ThreadLocalMapThreadLocalMap map = Thread.currentThread().threadLocals;//在ThreadLocalMap中//查找变量Entry e = map.getEntry(this);return e.value;}static class ThreadLocalMap {//内部是数组而不是MapEntry[] table;//根据ThreadLocal查找EntryEntry getEntry(ThreadLocal key) {//省略查找逻辑}//Entry定义static class Entry extends WeakReference<ThreadLocal> {Object value;}}}
使用demo
public class BaseTest {ThreadLocal<Long> longLocal = new ThreadLocal<>();ThreadLocal<String> stringLocal = new ThreadLocal<>();public void set() {longLocal.set(Thread.currentThread().getId());stringLocal.set(Thread.currentThread().getName());}public long getLong() {return longLocal.get();}public String getString() {return stringLocal.get();}}
Entry的key为什么要使用弱引用

每个thread中都有一个map成员变量(类型是ThreadLocal.ThreadLocalMap)。map中的key为一个个Threadlocal实例。 这个Map的确使用了弱引用,不过弱引用只是针对key。每个key都弱引用指向Threadlocal实例。所以当把Threadlocal实例置为null以后(或者说方法块执行完了之后,其内部的申明的new ThreadLocal实例)理应被释放了。但由于当前线程还存活,作为GCRoot扫描来说,ThreadLocalMap也存活,里面的key又是引用了已经实际无效的被释放的Threadlocal。
注意!假如每个key都强引用指向threadlocal,也就是上图虚线那里是个强引用,那么这个threadlocal就会因为和entry存在强引用无法被回收!造成内存泄漏 ,除非线程结束,线程被回收了,map也跟着回收。
依然出现的内存泄露问题
虽然上述的弱引用解决了key,也就是线程的ThreadLocal能及时被回收,但是value却依然存在内存泄漏的问题。
当把threadlocal实例置为null以后,没有任何强引用指向threadlocal实例,所以threadlocal将会被gc回收.
map里面的value却没有被回收.而这块value永远不会被访问到了. 所以存在着内存泄露,
因为存在一条从current thread连接过来的强引用.
只有当前thread结束以后, current thread就不会存在栈中,强引用断开, Current Thread, Map, value将全部被GC回收.
