Java 引用
2021-03-10 02:29
                         标签:寻址   dir   使用   rect   weak   不一致   ext   索引   扫描    date: 2020-12-08 15:42:56 ThreadLocal的设计初衷:提供线程内部的局部变量,在本线程内可以随意使用,隔离其他线程 每一个Thread对象,都包含一个  以  ThreadLocal 在 get、set 的时候会首先获取到 Thread.currentThread(),然后再根据线程拿到 threadLocals  这个map,然后在map中进行操作,保证了只是针对当前线程的变量进行操作 为什么要用到弱引用?避免内存溢出。为啥会内存溢出? 创建一个  简单来说就是,ThreadLocalMap 这块内存,除了 ThreadLocal 指向它,Thread 也指向它,ThreadLocal 本身并不存储值,它只是作为一个 key 来让线程从 ThreadLocalMap 获取 value 仅仅是把 在ThreadLocal的get、set方法以及扩容时,会清理掉key=null的Entry 首先在索引位置去拿到一个Entry e,如果e不为null并且key相同返回e;如果e为null或者key不一致则向下一个位置查询,如果下一个位置的key和当前需要查询的key相等,则返回对应的Entry,否则,如果key值为null,则擦除该位置的Entry,否则继续向下一个位置查询。 虽然ThreadLocal本身也做了避免内存泄露的优化,但是上述成功前提是需要调用get、set方法 => 大多数情况下还是手动调用 remove() 更好 => JDK 建议就是把  Java 引用 标签:寻址   dir   使用   rect   weak   不一致   ext   索引   扫描    原文地址:https://www.cnblogs.com/mxxct/p/14158332.html
updated: 2020-12-08 17:27:04Java 引用
1. 引用类型
import SoftReference
SoftReference对象,这个对象里会有一个value -> 这个value指向了堆中的一个对象,也就是真正的值
import WeakReference
WeakReference对象,这个对象里会有一个value -> 这个value指向了堆中的一个对象,也就是真正的值ThreadLocal
import PhantomReference
2. ThreadLocal中的弱引用
ThreadLocal.ThreadLocalMap threadLocals 的属性。static ThreadLocal为例,这个 map 的 key 就是 localVar,value 就是一个字符串,这个字符串是在每一个线程中,通过 localVar.set("xxx") 设置的
ThreadLocalMap 中的每一对 key,value 都是存放在 Entry 中的,而 Entry 继承了 WeakReference,并在构造函数中将 key 作为了弱引用/**
 * 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 WeakReferenceThread --> ThreadLocal.ThreadLocalMap 其中 localVar 是弱引用Thread 中含有指向 ThreadLocal 类下的 ThreadLocalMap 这个对象的变量ThreadLocal,如果不是弱引用, localVar = null,对应的ThreadLocalMap中的key就是null,理论上应该回收 ``ThreadLocal对象,但是并不会,因为ThreadLocal.ThreadLocalMap 还被某个线程强引用(生产上的线程多数都是一直在运行的),就会导致ThreadLocalMap中的内存一直无法被回收。现在是弱引用,即 localVar = null`,如果这时候GC扫描到了就可以回收,哪怕线程正在进行。
key置为null是不够的,因为value还是不会被回收掉,key=null的Entry的value还存在一个强引链 Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value,导致内存泄漏。所以正确的做法是static ThreadLocalprivate Entry getEntry(ThreadLocal> key) {
    int i = key.threadLocalHashCode & (table.length - 1);
    Entry e = table[i];
    if (e != null && e.get() == key)
        return e;
    else
        return getEntryAfterMiss(key, i, e);
}
private Entry getEntryAfterMiss(ThreadLocal> key, int i, Entry e) {
     Entry[] tab = table;
     int len = tab.length;
     while (e != null) {
         ThreadLocal> k = e.get();
         if (k == key)
             return e;
         if (k == null)
             expungeStaleEntry(i);
         else
             i = nextIndex(i, len);
         e = tab[i];
     }
     return null;
 }
ThreadLocal 变量定义成private static的,这样的话ThreadLocal的生命周期就更长,就会一直存在ThreadLocal的强引用,所以ThreadLocal也就不会被回收,也就能保证任何时候都能根据ThreadLocal的弱引用访问到Entry的value值,所以我们需要调用 remove,防止内存泄露。
下一篇:Java自定义异常类