前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ThreadLocal实现原理和最佳实践

ThreadLocal实现原理和最佳实践

作者头像
十毛
发布2019-12-12 16:23:09
6990
发布2019-12-12 16:23:09
举报

ThreadLocal在多线程项目中使用很多,简化了多线程对资源的使用,

ThreadLocal常用场景

适用于每个线程需要有自己单独的实例,实例需要在多个方法中共享,但不希望被多线程共享

  • Web请求的用户身份态:Session
  • 请求的链路跟踪:traceId
  • SimpleDateFormat:因为SimpleDateFormat不是线程安全的

ThreadLocal实现原理

`ThreadLocal`内存布局

图中实线是引用,虚线是弱引用(不会阻止内存的回收)

  • ThreadLocal中的数据实际上都是保存在Thread的成员变量ThreadLocal.ThreadLocalMap ThreadLocals中,ThreadLocalMap是一个Key是ThreadLocal`,Value是泛型T的一个Map
  • ThreadLocal本身并不存储值,只是作为一个ThreadLocalMap中的一个key
  • Hash冲突的解决方法:开放定址法(跟HashMap使用列表法和红黑树不同)

ThreadLocal为什么会内存泄漏

从表面上看内存泄漏的根源在于使用了弱引用。网上的文章大多着重分析ThreadLocal使用了弱引用会导致内存泄漏,但是另一个问题也同样值得思考:为什么使用弱引用而不是强引用?

我们先来看看官方文档的说法:

To help deal with very large and long-lived usages, the hash table entries use WeakReferences for keys. 为了应对非常大和长时间的用途,哈希表使用弱引用的 key。

下面我们分两种情况讨论:

  • key 使用强引用:引用的ThreadLocal的对象被回收了,但是ThreadLocalMap还持有ThreadLocal的强引用,如果没有手动删除,ThreadLocal不会被回收,导致Entry内存泄漏。
  • key 使用弱引用:引用的ThreadLocal的对象被回收了,由于ThreadLocalMap持有ThreadLocal的弱引用,即使没有手动删除,ThreadLocal也会被回收。value在下一次ThreadLocalMap调用set,get,remove的时候会被清除。 比较两种情况,我们可以发现:由于ThreadLocalMap的生命周期跟Thread一样长,如果都没有手动删除对应key,都会导致内存泄漏,但是使用弱引用可以多一层保障:弱引用ThreadLocal不会内存泄漏,对应的value在下一次ThreadLocalMap调用set,get,remove的时候会被清除。

因此,ThreadLocal内存泄漏的根源是:由于ThreadLocalMap的生命周期跟Thread一样长,如果没有手动删除对应key就会导致内存泄漏,而不是因为弱引用。 因此,ThreadLocal内存泄漏的根源是:由于ThreadLocalMap的生命周期跟Thread一样长,如果没有手动删除对应key就会导致内存泄漏,而不是因为弱引用。

自问自答

  • 为什么数据没有保存在ThreadLocal,而是Thread? 因为线程私有数据应该跟线程生命周期一致
  • 为什么Entry.value不使用WeakReference? 因为ThreadLocal可能还存在强引用,同时value没有外部的强引用,如果设置为WeakReference就可能导致ThreadLocal.get()拿不到对应的value了

最佳实践

  • 使用完ThreadLocal后,执行remove操作,避免出现内存溢出情况。特别是在线程复用的场景,不但可以避免内存溢出,还避免了数据的错误复用

参考

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ThreadLocal常用场景
  • ThreadLocal实现原理
  • ThreadLocal为什么会内存泄漏
  • 自问自答
  • 最佳实践
  • 参考
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档