ThreadLocal 小结

  • ThreadLocal
    • 结构

      Untitled

      • Thread -> ThreadLocalMap ->Entry(WeakReference) -> [Key(ThreadLocal):Value(Object)]
    • 内存泄漏问题
      • ThreadLocal被回收了,ThreadLocalMap的Key没有强引用,但Value还有。首先在非线程池环境不会有长期性的这个问题,因为Thread回收后,ThreadLocal也就被回收了,造成泄漏的情况是: 线程被复用 && ThreadLocal 被回收 && 不再调用ThreadLocal的get set remove 等方法
      • 为什么Key不是强引用? 因为若是强引用,当ThreadLocal置为null时,由于ThreadLocalMap还存在对其强引用,则导致无法回收。弱引用的真正目的是回收value
      • 为什么不把value设置成弱引用? 因为这样value就总是弱引用,哪怕threadlocalmap在使用时,value也会被回收,和实际场景不符

      po_diagram.png

    • 线程池复用问题

      • 原因:线程池是复用的,导致提交任务时的线程上下文和执行任务的线程上下文不一致
      • 使用TTL解决
        • 原理见下方对比
    • 使用要点
      • 使用完成后调用 remove(),会把 key 置为 null,触发检测所有 key null 的 entry,把 value 置为 null,方便 gc
    • 对比
      • InheritableThreadLocal
        • 原理是在 Thread 构造时,会把调用方线程的inheritableThreadLocals复制到构造的子线程中if (parent.inheritableThreadLocals != null) this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
      • TransmittableThreadLocal
        • 原理是对runnable即提交的任务进行封装为TtlRunnable,流程是
        1. 初始化 TtlRunnable 时,对当前线程(提交任务的线程)的TransmittableThreadLocal进行快照(captured())
        2. 设置到前执行任务的线程中(replay(…))
        3. 执行任务 (run())
          4. 恢复执行线程上下文 restore(backup)
    • 应用
      • PageHelper 的 pageInfo
      • dubbo 的 rpcContext
      • 日志 MDC
      • Spring 声明式事务(TL 管理 connection)
      • 对静态 SimpleDateFormat 优化

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

Scroll to Top