• JDK ThreadLocal


    2019-03-29 周五 10:45 下午

    1. ThreadLocal 回顾:
      主要看 ThreadLocal#get()方法:
      public T get() {
          Thread t = Thread.currentThread();
          // 拿到当前线程中保存的 map
          ThreadLocalMap map = getMap(t); 
          if (map != null) {
              // 以 this (也就是用户创建的 ThreadLocal 对象)为 key
              // 获取到一个 Entry 对象,然后返回 value
              ThreadLocalMap.Entry e = map.getEntry(this);
              if (e != null) {
                  @SuppressWarnings("unchecked")
                  T result = (T)e.value;
                  return result;
              }
          }
          // 当 map 为 null 时,调用初始化方法,包括 ThreadLocalMap 的创建
          // 以及初始化 value
          return setInitialValue();
      }
      

    ThreadLocal 示意图

    1. 内存泄漏相关
      ThreadLocalMap 中的键值对是用 Entry 存储的,Entry 继承了 WeakReference 代码如下:

          static class Entry extends WeakReference<ThreadLocal<?>> {
              /** The value associated with this ThreadLocal. */
              Object value;
      
              Entry(ThreadLocal<?> k, Object v) {
                  super(k); // 调用父类构造方法,弱引用
                  value = v;// 强引用
              }
          }
      

      从构造方法中可以看到 entry 对 k 的引用是一个弱引用,对 v 的引用则是强引用。
      对 k 使用弱引用的原因是:当 map 外部没有对 ThreadLocal 对象的强引用时,说明这个 ThreadLocal 对象不需要了,k 在下一次 GC 时就会被回收。 如果不采用弱引用,因为某些线程的 map 对 ThreadLocal 对象还有强引用,导致其无法被回收掉。

      虽然对 k 使用了弱引用解决了前面提到的内存泄漏的问题,但是有引发了另一个内存泄漏的问题:
      如果线程一直在运行,那么该线程持有的 map 就不会被销毁,当外部没有对 ThreadLocal 对象的强引用时,经过一轮 GC,对应的 Entry 就变成了 null -> value 的情况,对 value 的引用是强引用,这就导致 Entry 对象始终无法释放掉。
      针对这个问题:在 ThreadLocalMap 的 set() 和 rehash()等方法中,会将 key 为 null 的 Entry 的 value 置为 null,使得 Entry 对象可以被回收。

      理论上来讲,ThreadLocal 还是可能会出现内存泄漏的,因为最后将 Entry 的 value 置为 null 的操作,不够及时(待确认)。
      建议:

      1. 一直持有 ThreadLocal 对象的强引用
      2. 如果当前线程不需要本地变量时,显示的调用 Threadloca 对象的 remove()方法

    参考

  • 相关阅读:
    vs编译错误error C2059 由extern "C"导致的错误处理
    原生JS:响应式轮播图
    JSP用户关注取关实现
    JSP和AJAX实现登录注册
    MySQL常用命令
    offsetWidth/getBoundingRect()/scrollWidth/client用法总结
    画廊相册—原生JavaScript实现
    《JavaScript DOM 编程艺术》读书笔记
    天猫网页前端实现
    Docker安装和配置(链接集合)
  • 原文地址:https://www.cnblogs.com/magexi/p/11619901.html
Copyright © 2020-2023  润新知