ThreadLocal与WeakReference

ThreadLocal与WeakReference每个线程中都保存着一个threadLocals实例

 转自 http://cache.baiducontent.com/

ThreadLocal是面试中比较容易碰上的问题,一般会要求讲解它的实现原理以及存在的问题。最近在美团的面试中聊到这个问题,虽然去年有看过并收藏了关于ThreadLocal的一些文章但目前几乎忘了干净(还是实践以及理解的不够没有形成记忆 …),所以趁着这个机会好好的总结记录一下。

ThreadLocal的实现机制不复杂,它将自身实例作为key,和需要保存的value一起存入到当前线程的一个map当中,代码可以简单的描写为(当然实际的代码并不是这样):



Thread.currentThread().threadLocals.put(
this
, value);
// threadLocal.set(T)
Thread.currentThread().threadLocals.get(
this
);
// threadLocal.get()

ThreadLocal实现中特别值得注意的是1点:每个线程中都保存着一个threadLocals实例,该实例是Map接口的实现 – ThreadLocalMap。而这个类实现的特殊地方在于,ThreadLocalMap中的Entry中的key类型是WeakReference<ThreadLocal>而非ThreadLocal。为什么ThreadLocalMap中需要使用WeakReference作为key类型,那么首先需要理解WeakReference的意义。

WeakReference是Java语言规范中为了区别直接的对象引用(程序中通过构造函数声明出来的对象引用)而定义的另外一种引用关系。WeakReference标志性的特点是:reference实例不会影响到被应用对象的GC回收行为(即只要对象被除WeakReference对象之外所有的对象解除引用后,该对象便可以被GC回收),只不过在被对象回收之后,reference实例想获得被应用的对象时程序会返回null。

理解了WeakReference之后,ThreadLocalMap使用它的目的也相对清晰了:当threadLocal实例可以被GC回收时,系统可以检测到该threadLocal对应的Entry是否已经过期(根据reference.get() == null来判断,如果为true则表示过期,程序内部称为stale slots)来自动做一些清除工作,否则如果不清除的话容易产生内存无法释放的问题:value对应的对象即使不再使用,但由于被threadLocalMap所引用导致无法被GC回收。实际代码中,ThreadLocalMap会在set,get以及resize等方法中对stale slots做自动删除(set以及get不保证所有过期slots会在操作中会被删除,而resize则会删除threadLocalMap中所有的过期slots)。当然将threadLocal对象设置为null并不能完全避免内存泄露对象,最安全的办法仍然是调用ThreadLocal的remove方法,来彻底避免可能的内存泄露。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:http://bianchenghao.cn/36534.html

(0)
编程小号编程小号

相关推荐

发表回复

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