ThreadLocal 源码解读

ThreadLocal是什么

ThreadLocal提供了线程的局部变量,每个线程访问独立的变量副本,实现了线程的数据隔离。

ThreadLocal实现原理

每个线程Thread实例中包含两个ThreadLocalMap实例:threadLocalsinheritableThreadLocals,读取ThreadLocal实例时,以ThreadLocal实例为key从当前线程的threadLocals字段读取对应的值。设置值时,向当前线程的threadLocals字段中写入对应的key和value。ThreadLocalMap中的 Entry 使用弱引用引用了ThreadLocal,并强引用了ThreadLocal对应的线程本地变量副本。当 ThreadLocal 变量被回收后,该映射对应的键变为 null,ThreadLocalMap中对应的 Entry 无法被手动移除,进而使得线程的变量副本被该 Entry引用而无法被回收造成内存泄漏。

ThreadLocalMap与内存泄漏

ThreadLocalMap 的每个 Entry 都是一个对键(ThreadLocal)的弱引用,同时 Entry 又包含了一个对值(当前线程的变量副本)的强引用。当没有强引用指向 ThreadLocal 变量时,ThreadLocal可被回收,但Entry中包含的变量副本不能自动释放。

防止ThreadLocal内存泄漏

ThreadLocalMap 的 set 方法中,通过 replaceStaleEntry 方法将所有键为 null 的 Entry 的值设置为 null,从而使得该值可被回收。另外,会在 remove方法、rehash 方法中通过 expungeStaleEntry 方法将键为 null 的 Entry 的值设为null并将Entry设置为 null 从而使得该 Entry 及对应的值可被回收。通过这种方式,ThreadLocal 可防止内存泄漏。

为了及时的内存回收,可以调用ThreadLocal.remove()方法主动移除对应的Entry及线程变量副本。

总结

  1. ThreadLocal 并不解决线程间共享数据的问题
  2. ThreadLocal 通过隐式的在不同线程内创建独立实例副本避免了实例线程安全的问题
  3. 每个线程持有一个 Map 并维护了 ThreadLocal 对象与具体实例的映射,该 Map 由于只被持有它的线程访问,故不存在线程安全以及锁的问题
  4. ThreadLocalMap 的 Entry 对 ThreadLocal 的引用为弱引用,避免了 ThreadLocal 对象无法被回收的问题
  5. ThreadLocalMap 的 set 方法通过调用 replaceStaleEntry 方法回收键为 null 的 Entry 对象的值(即为具体实例)以及 Entry 对象本身从而防止内存泄漏
  6. ThreadLocal 适用于变量在线程间隔离但在方法间共享的场景

ThreadLocal使用案例

  1. DataSource中的getConnection()方法
  2. Spring Security中的ThreadLocalSecurityContextHolderStrategy
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1. 背景 ThreadLocal源码解读,网上面早已经泛滥了,大多比较浅,甚至有的连基本原理都说的很有问题,包括...
    小陈阿飞阅读 1,372评论 2 56
  • 一.threadlocal概述 顾名思义线程本地存储,如果定义了一个threadlocal对象,每个线程往这个th...
    Gorden_Tam阅读 463评论 0 0
  • 原文链接:Java进阶(七)正确理解Thread Local的原理与适用场景 - 郭俊Jason - 博客园 Th...
    Walter_Hu阅读 805评论 0 1
  • 在清水中放入一颗糖不会太甜,但放入一勺醋就会很酸。捡到钱不会太高兴,丢了钱却会懊恼不堪。人不能因为一件喜事高兴一整...
    橙子不倒翁阅读 183评论 0 0
  • 今天是“世界蜜蜂日”天气预报出奇的准,中雨转阵雨轮番上阵,约好去嗡嗡乐玩并且签到行走齐鲁。带着目的性冒雨来到...
    Anne惠阅读 232评论 0 1