重点:ThreadLocal问题总结

1. ThreadLocal是什么?(作用)

是实现线程局部变量的工具类。让每个访问该变量的线程都拥有自己的独立副本,实现线程隔离。

2. ThreadLocal的实现原理

ThreadLocal 是通过每个线程内部持有一个私有的 ThreadLocalMap (ThreadLocal 类的一个静态内部类)来实现的。

当我们调用 set 方法时,实际上是获取当前线程对象,并把数据存入这个线程自带的 Map 中,Key 就是当前的 ThreadLocal 对象。Value可以是任意类型。当调用ThreadLocal的get()方法的时候,会先找到当前线程的ThreadLocalMap,然后再找到对应的值。

3. ThreadLocal的优点

1️⃣ 每个线程访问的变量副本均独立,避免了共享变量引起的线程安全问题。 

2️⃣ 实现了变量的线程独占,使变量不需要同步处理,避免资源竞争。

3️⃣ 可用于跨方法、跨类时传递上下文数据,不需要在方法间传递参数。

4. ThreadLocal的问题

问题:内存泄露。ThreadLocalMap 的 Key 是 弱引用,但 Value 是强引用。如果一个线程一直在运行,并且 value 一直指向某个强引用对象,那么这个对象就不会被回收,从而导致内存泄漏。

解决方案:使用完 ThreadLocal 后,及时调用 remove() 方法释放内存空间。

补充:

ThreadLocalMap 内部维护了一个 Entry 类型的数组。每一个 Entry 都是一个键值对:

Key:指向 ThreadLocal 对象的弱引用(WeakReference)。

Value:具体要存储的变量副本(强引用)

什么是弱引用,什么是强引用?

强引用:User user = new User("沉默王二") 中,user 就是一个强引用, new User("沉默王二") 就是强引用对象。当 user 被置为 null 时( user = null ), new User("沉默王二") 对象就会被垃圾回收;否则即便是内存空间不足,JVM 也不会回收 new User("沉默王二") 这个强引用对象,宁愿抛出 OutOfMemoryError。

弱引用:调用 set 方法后,会将 key = new ThreadLocal<>() 放入 ThreadLocalMap 中,此时的 key 是一个弱引用对象。当 JVM 进行垃圾回收时,如果发现了弱引用对象,就会将其回收。

当ThreadLocal与线程池结合使用时,可能会导致内存泄漏的问题。

这是因为线程池中的线程在执行完任务后,并不会被销毁,而是重新放入线程池中以供重用。如果在任务执行过程中使用了ThreadLocal,并且没有手动清除其中的数据,那么这些数据会一直保留在线程中。由于线程池中的线程是可重用的,当线程被复用时,原来线程中遗留的ThreadLocal数据依然存在,如果没有及时清理,这些数据会一直占用内存,并且对应的ThreadLocal实例也不会被回收。随着线程池的不断使用,内存中积累的无用ThreadLocal实例和数据也会越来越多,从而导致内存泄漏。

(为什么线程池会存在复用问题?因为 ThreadLocal 的生命周期是和线程绑定的。在线程池中,线程在执行完任务后不会销毁,如果前一个任务没有调用 remove() 清理数据,那么下一个任务在复用该线程时,就会读取到上个任务残留的旧数据,造成‘数据污染’。)

  为了避免这个问题,使用ThreadLocal时需要特别注意在使用完毕后及时清理数据。可以通过在任务执行完毕后手动调用ThreadLocal的remove()方法(在finally中)来清除对应线程的ThreadLocal数据。另外,还可以使用线程池的钩子函数,在线程池中的线程执行完任务后自动清理ThreadLocal数据。

##牛客AI配图神器#
全部评论

相关推荐

04-15 12:30
门头沟学院 Java
攒人品中,祝大家都能拿到满意的Offer!1.实习拷打2.手撕代码:三数之和,问了点边界情况3.从基础开始吧。你知道这个&nbsp;string&nbsp;啊,&nbsp;string&nbsp;buffer,&nbsp;string&nbsp;builder&nbsp;这三个类有什么区别吗?4.队列的一些方法:插入用啥,查看队首用啥,出队用啥?还有栈跟队列的区别5.双亲委派模型了解吗,设计的目的是啥?它怎么防止重复加载?,有没有打破双亲委派模型的例子?为什么要打破呢?6.然后你用过反射吗?反射是什么?应用场景?7.所以你刚才说那个注解,那个注解的原理是什么?讲一下注解的原理8.然后&nbsp;IOC&nbsp;知道吗?讲一下&nbsp;IOC。9.怎么声明一个对象?(@Autowired&nbsp;和构造器)10.幂等性了解吗?怎么实现幂等性?11.线程跟进程的区别?12.线程池的参数?13.那核心线程数、最大线程数是表示什么含义呢?14.那他一般核心线程数怎么设置的?为什么要这么设置?15.一般保证多线程安全的方法有什么?16.synchronized和&nbsp;volatile&nbsp;的区别?synchronized底层原理?锁升级的机制?为什么要锁升级?17.ConcurrentHashMap怎么保证线程安全?18.ThreadLocal在项目中有用过吗?内存泄漏?19.常用的&nbsp;SQL&nbsp;优化的技巧?20.MySQL常用的两种引擎,区别?(只具体答了InnoDB,MyISAM只回答了个名字)21.redolog&nbsp;undolog22.什么叫不可重复读?23.那个我们怎么看一个&nbsp;SQL&nbsp;语句就是它的查询性能呢?24.OSI七层模型
查看22道真题和解析
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务