ThreadLocal面试题
两种应用场景:
1、线程之间做数据隔离;
2、单个线程中做参数传递;
通常,在业务代码中,使用的是static的变量
这里需要理解,Thread中的Map,key是this,也就是ThreadLocal对象的指针哈希值
为什么使用完要remove掉,比如在线程池中,线程被反复使用,可能到期这个ThreadLocalMap变得非常的大,占用内存;
示例代码:
class UserContextHolder{
public static ThreadLocal<User> holder = new ThreadLocal<>();
}
内存泄露怎么理解?
演示代码
public class Test {
public static void main(String[] args) {
ThreadLocal local = new ThreadLocal();
local.set(new Test());
local = null;
// 手动触发GC,此时ThreadLocal被回收,那么value是否被回收呢?
System.gc();
// GC是异步执行的,主线程Sleep一会,等待对象回收
ThreadUtil.sleep(1000);
}
// 对象被回收时触发
@Override
protected void finalize() throws Throwable {
System.err.println("对象被回收...");
}
}
https://juejin.cn/post/6932807532587810824
可以参考这个帖子
总结:
线程池的线程不会被回收;需要记得使用remove方法!
Entry中的Key设计为WeakReference的方式
一个对象可以被一个变量通过强引用的方式指向,也可以被另外一个变量通过若应用的方式指向;(这里要注意,引用是一个指针指向)
当这个对象只被若应用指向的时候,那么这个对象就会被回收,不管内存够不够使用;
如果这个ThreadLocal强引用没有了,只有弱引用,那么就会被回收,就成为了null值;
如果这个Entry对象的Key为了null,但是value还是存在,那么这个value就被泄露了
避免的方式,下面基本都是使用了第二点,所以可以认为不存在啊
当然,就是使用不规范,ThreadLocal内部也做了一些优化,比如:
调用set()方法时,ThreadLocal会进行采样清理、全量清理,扩容时还会继续检查。
调用get()方法时,如果没有直接命中或者向后环形查找时也会进行清理。
调用remove()时,除了清理当前Entry,还会向后继续清理。
https://www.51cto.com/article/708441.html