当被应用的强引用失去后,强引用关联的这个引用也就是虚引用相关的分配就会被回收
以ThreadLocal<T>为例1.进行塞值 public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { map.set(this, value); } else { createMap(t, value); } } 2.一开始塞值肯定不存在就得走这个方法 void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); } 3.里面这个firstKey就是ThreadThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) { table = new Entry[INITIAL_CAPACITY]; int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1); table[i] = new Entry(firstKey, firstValue); size = 1; setThreshold(INITIAL_CAPACITY); 4.构建个Entrytable[i] = new Entry(firstKey, firstValue); 5.Entry里面长这样,构造参数里面有个super(k)static class Entry extends WeakReference<ThreadLocal<?>> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; } }
继续看顶层引用
默认这个queue是空,先不管它
一直到最底层
回头再来说,ThreadLocal的缺点,缺点有个啥来着,叫内存泄露,
ThreadLocal<String> threadLocal = new ThreadLocal<>();//直接new一个出来,这个是强引用threadLocal.set("111");//塞值之后,把Thread和值放到里面的map里面去 一般情况下,threadLocal 消失后,塞值因为弱引用会被垃圾回收器回收。大并发情况下来不及回收,里面的map里面key引用的值来不及释放,没有及时被垃圾回收器回收,就造成了内存泄漏。
于是之前讲的InheritableThreadLocal就发挥作用了。
但是据我观察,jdk17之后
虽然弱引用机制没有改变,但是 JDK 17 中内存管理方面的改进间接增强了对ThreadLocal相关内存的控制。
例如,JDK 17 的垃圾回收器(如 ZGC 和 Shenandoah GC)的优化使得内存回收更加高效和及时。 在高并发场景下,这些优化后的垃圾回收器能够更频繁地检查内存中的弱引用对象。
当ThreadLocal对象作为弱引用被回收后,
内存管理系统可以更快地识别并处理对应的ThreadLocalMap中的Entry,减少了无效Entry(键已被回收但值还在)在内存中停留的时间