车驰夜幕|面试时被问到ThreadLocal别慌,你要的答案都在这里( 五 )
为什么要做这样的清除?
我们知道entry对象里面包含了threadLocal和value , threadLocal是WeakReference(弱引用)的referent 。 每次垃圾回收期触发GC的时候 , 都会回收WeakReference的referent , 会将referent设置为null 。 那么table数组中就会存在很多threadLocal = null 但是 value不为空的entry , 这种entry的存在是没有任何实际价值的 。 这种数据通过getEntry是获取不到值 , 因为它里面有if (e != null && e.get() == key)这句判断 。
为什么要使用WeakReference(弱引用)?
如果使用强引用 , ThreadLocal在用户进程不再被引用 , 但是只要线程不结束 , 在ThreadLocalMap中就还存在引用 , 无法被GC回收 , 会导致内存泄漏 。 如果用户线程耗时非常长 , 这个问题尤为明显 。
另外在使用线程池技术的时候 , 由于线程不会被销毁 , 回收之后 , 下一次又会被重复利用 , 会导致ThreadLocal无法被释放 , 最终也会导致内存泄露问题 。
4.ThreadLocal有哪些坑
内存泄露问题:
ThreadLocal即使使用了WeakReference(弱引用)也可能会存在内存泄露问题 , 因为 entry对象中只把key(即threadLocal对象)设置成了弱引用 , 但是value值没有 。 还是会存在下面的强依赖:
Thread -> ThreaLocalMap -> Entry -> value
要解决这个问题就需要调用get()、set(T value) 或 remove()方法 。 但是 get()和set(T value) 方法是基于垃圾回收器把key回收之后的基础之上触发的数据清理 。 如果出现垃圾回收器回收不及时的情况 , 也一样有问题 。
所以 , 最保险的做法是在使用完threadLocal之后 , 手动调用一下remove方法 , 从源码可以看到 , 该方法会把entry中的key(即threadLocal对象)和value一起清空 。
线程安全问题:
可能有些朋友认为使用了threadLocal就不会出现线程安全问题了 , 其实是不对的 。 假如我们定义了一个static的变量count , 多线程的情况下 , threadLocal中的value需要修改并设置count的值 , 它一样有问题 。 因为static的变量是多个线程共享的 , 不会再单独保存副本 。
5.总结
【车驰夜幕|面试时被问到ThreadLocal别慌,你要的答案都在这里】1.每个线程都有一个threadLocalMap对象 , 每个threadLocalMap里面都包含了一个entry数组 , 而entry是由key(即threadLocal)和value(数据)组成 。
2.entry的key是弱引用 , 可以被垃圾回收器回收 。
3.threadLocal最常用的这四个方法:get() ,initialValue() , set(T value) 和 remove() , 除了initialValue方法 , 其他的方法都会调用expungeStaleEntry方法做key==null的数据清理工作 。
4.threadLocal可能存在内存泄露和线程安全问题 , 使用完之后 , 要手动调用remove方法 。
5.其实实际项目中使用threadLocal的机会还是挺多的 , 比如有些参数 , 你在多个方法中都可能会使用 , 但又不想在多个方法直接层层传递 , 这个时候就可以使用threadLocal 。 最典型使用threadLocal的场景是事务 和 MDC日志功能 。
朋友们如果喜欢这篇文章的话 , 请关注一下我的公众账号 :苏三说技术 , 后面会有很多干货分享 , 谢谢大家 。
- 小鹰说科技|美军警告:别想分割封锁我们,美火速增兵叙利亚!大批装甲车驰援
- 通过率只有3%的面试还难,湖畔大学的学员答辩都在讨论什么?
- 上观新闻|夜幕下的南京路步行街东拓段,灯光璀璨,景色更加迷人
- 柚子在野区|【当当与您早知道】月亮不“孤单”
- 车驰夜幕|美国GPS卫星精度0.4米,俄卫星的精度1.2米,中国北斗呢?
- 车驰夜幕|联合国向你发来活动邀请:与全球尖端人士探讨关注自然的真谛
- 陕西省教育厅|定了!2020年教师资格证笔试、面试时间公布
- 车驰夜幕|简单聊聊处理器的核显
- 模范爸爸|「干货满满」1.5w字初中级前端面试复习总结
- 澎湃新闻|非全日制研究生通过面试后被取消资格?官方:前期审核失误