ThreadLocal

2021-05-27  本文已影响0人  cqxxxxxxxx
注意点
  1. 线程本地变量

    即每个线程对象都维护了自己的ThreadLocalMap,只访问自己的Map,所以是安全的。

    Thread类里面有ThreadLocal.ThreadLocalMap属性,threadLocals和inheritableThreadLocals,以此保证每个线程都维护一份自己的数据

  2. 内存泄露

    ThreadLocalMap的Entry[] table中Entry继承了WeakReference,其中Key即ThreadLocal对象是弱引用,是为了避免内存泄露。 为什么能避免呢? 如下

    已知存在Thread->ThreadLocalMap->Entry->Key(ThreadLocal)的引用联关系。假设ThreadLocalMap.Entry中的ThreadLocal不设置成弱引用,那么当你在一个方法体内大量创建ThreadLocal并进行set操作之后,即使你该方法执行完了,创建的ThreadLocal对象引用也没有逃逸出该方法,但是它永远GC不掉,因为任然有开头说的Thread这边的强引用,所以这种无用对象一直堆积而得不到GC,就产生了内存泄露。

    不过一般我们都不会在方法体内创建ThreadLocal,一般是private static ThreadLocal创建的。所以也不会泄露问题。

    image

    引用链关系图

    1. ThreadLocalMap哈希冲突

      set方法时候处理hash冲突的方式是调用nextIndex(index, length)方法,其实就是在当前index基础上+1

流程

  1. private static ThreadLocal<String> threadLocal = new ThreadLocal<>();

    new ThreadLocal<>()是空构造器,只不过会初始化实例变量,threadLocalHashCode

  2. threadLocal.set("nmm")

 public void set(T value) {
     //获取当前线程的ThreadLocalMap对象
     Thread t = Thread.currentThread();
     ThreadLocalMap map = getMap(t);
     //存在则用该ThreadLocal作为Key,设置进去
     if (map != null)
     map.set(this, value);
     else
     //不存在则创建map,同时设置value
     createMap(t, value);
     }
3.  `threadLocal.get("nmm")`
public T get() {
         //获取当前线程绑定的map
         Thread t = Thread.currentThread();
         ThreadLocalMap map = getMap(t);
         if (map != null) {
         //map中查找该ThreadLocal的entry,返回值
         ThreadLocalMap.Entry e = map.getEntry(this);
         if (e != null) {
         @SuppressWarnings("unchecked")
         T result = (T)e.value;
         return result;
         }
         }
         return setInitialValue();
         }
    4.  `threadLocal.remove()`主要就调用ThreadLocalMap.remove方法
public void remove() {
             ThreadLocalMap m = getMap(Thread.currentThread());
             if (m != null)
             m.remove(this);
             }

             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) {
             //把Reference的referent关联的ThreadLocal 清除
             e.clear();
             //清理map中key为null的value,跟weakHashMap一样
             expungeStaleEntry(i);
             return;
             }
             }
             }
上一篇下一篇

猜你喜欢

热点阅读