美文网首页Java
ThreadLocal与WeakReference

ThreadLocal与WeakReference

作者: 吃猫的老鼠 | 来源:发表于2015-05-27 11:05 被阅读1201次

    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。为什么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方法,来彻底避免可能的内存泄露。

    相关文章

      网友评论

      • 小贱不要走远:里面没有map的实现,只是一个数组。
      • zzmarquis:ThreadLocalMap不是Map借口的实现,它没有实现任何借口也没有继承任何类,它内部的数据结构实际上只是一个数组:Entry[] table,只不过用来HASH算法来做散列。

      本文标题:ThreadLocal与WeakReference

      本文链接:https://www.haomeiwen.com/subject/egurqttx.html