呵呵,你这是在背面试题吧?ThreadLocal使用中会有那些坑?
Posted xhmj12
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了呵呵,你这是在背面试题吧?ThreadLocal使用中会有那些坑?相关的知识,希望对你有一定的参考价值。
相关阅读:杭州程序员从互联网跳央企,晒一天工作和收入,网友:待一年就废
来源:blog.csdn.net/zzg1229059735/article/details/82715741
本次给大家介绍重要的工具ThreadLocal。讲解内容如下,同时介绍什么场景下发生内存泄漏,如何复现内存泄漏,如何正确使用它来避免内存泄漏。
ThreadLocal是什么?有哪些用途?
首先介绍Thread类中属性threadLocals:
/* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
我们发现Thread并没有提供成员变量threadLocals的设置与访问的方法,那么每个线程的实例threadLocals参数我们如何操作呢?这时我们的主角:ThreadLocal就登场了。
所以有那么一句总结:ThreadLocal是线程Thread中属性threadLocals的管理者。
映射到我们要说的ThreadLocal
ThreadLocal如何使用
为了更直观的体会ThreadLocal的使用我们假设如下场景
我们创建一个ThreadLocal管理类:
测试程序如下:我们同一个线程不断get,测试id是否变化,同时测试完成后我们就将其释放掉。搜索公众号互联网架构师回复“2T”,送你一份惊喜礼包。
ThreadLocal原理
①ThreadLocal类结构及方法解析:
上图可知:ThreadLocal三个方法get, set , remove以及内部类ThreadLocalMap
②ThreadLocal及Thread之间的关系:
从这张图我们可以直观的看到Thread中属性threadLocals,作为一个特殊的Map,它的key值就是我们ThreadLocal实例,而value值这是我们设置的值。
③ThreadLocal的操作过程:
我们以get方法为例:
set的过程也类似:搜索公众号互联网架构师回复“2T”,送你一份惊喜礼包。
ThreadLocal使用有哪些坑及注意事项
我们来看下为什么说ThreadLocal会引起内存泄漏,什么场景下会导致内存泄漏?搜索公众号互联网架构师回复“2T”,送你一份惊喜礼包。
先回顾下什么叫内存泄漏,对应的什么叫内存溢出
显然是TreadLocal在不规范使用的情况下导致了内存没有释放。
红框里我们看到了一个特殊的类WeakReference,同样这个类,应用开发者也同样很少使用,这里简单介绍下吧
既然WeakReference在下一次gc即将被回收,那么我们的程序为什么没有出问题呢?
①所以我们测试下弱引用的回收机制:
这一种存在强引用不会被回收。
这里没有强引用将会被回收。
上面演示了弱引用的回收情况,下面我们看下ThreadLocal的弱引用回收情况。
②ThreadLocal的弱引用回收情况
下面我们模拟复现ThreadLocal导致内存泄漏:
1.为了效果更佳明显我们将我们的treadlocals的存储值value设置为1万字符串的列表:
class ThreadLocalMemory
// Thread local variable containing each thread's ID
public ThreadLocal<List<Object>> threadId = new ThreadLocal<List<Object>>()
@Override
protected List<Object> initialValue()
List<Object> list = new ArrayList<Object>();
for (int i = 0; i < 10000; i++)
list.add(String.valueOf(i));
return list;
;
// Returns the current thread's unique ID, assigning it if necessary
public List<Object> get()
return threadId.get();
// remove currentid
public void remove()
threadId.remove();
public static void main(String[] args)
throws InterruptedException
// 为了复现key被回收的场景,我们使用临时变量
ThreadLocalMemory memeory = new ThreadLocalMemory();
// 调用
incrementSameThreadId(memeory);
System.out.println("GC前:key:" + memeory.threadId);
System.out.println("GC前:value-size:" + refelectThreadLocals(Thread.currentThread()));
// 设置为null,调用gc并不一定触发垃圾回收,但是可以通过java提供的一些工具进行手工触发gc回收。
memeory.threadId = null;
System.gc();
System.out.println("GC后:key:" + memeory.threadId);
System.out.println("GC后:value-size:" + refelectThreadLocals(Thread.currentThread()));
// 模拟线程一直运行
while (true)
此时我们如何知道内存中存在memory leak呢?
我们可以借助jdk提供的一些命令dump当前堆内存,命令如下:
jmap -dump:live,format=b,file=heap.bin <pid>
然后我们借助MAT可视化分析工具,来查看对内存,分析对象实例的存活状态:搜索公众号互联网架构师回复“2T”,送你一份惊喜礼包。
这里我们可以确定的是ThreadLocalMap实例的Entry.value是没有被回收的。
最后我们要确定Entry.key是否还在?打开Dominator Tree,搜索我们的ThreadLocalMemory,发现并没有存活的实例。
以上我们复现了ThreadLocal不正当使用,引起的内存泄漏。demo在这里。
所以我们总结了使用ThreadLocal时会发生内存泄漏的前提条件:
我们看到ThreadLocal出现内存泄漏条件还是很苛刻的,所以我们只要破坏其中一个条件就可以避免内存泄漏,单但为了更好的避免这种情况的发生我们使用ThreadLocal时遵守以下两个小原则:
1、985副教授工资曝光
2、心态崩了!税前2万4,到手1万4,年终奖扣税方式1月1日起施行~
3、雷军做程序员时写的博客,很强大!
4、人脸识别的时候,一定要穿上衣服啊!
5、清华大学:2021 元宇宙研究报告!
6、绩效被打3.25B,员工将支付宝告上了法院,判了
以上是关于呵呵,你这是在背面试题吧?ThreadLocal使用中会有那些坑?的主要内容,如果未能解决你的问题,请参考以下文章
就Android内卷的程度,你只背背面试题,根本找不到好工作