文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

阿里二面:ThreadLocal为什么会内存泄露

2024-12-01 13:58

关注

ThreadLocal基础部分

ThreadLoal的作用

保存线程的独立变量,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数之间公共变量传递麻烦。

使用场景

需要给不同的线程保存不同的信息时。

基础使用

public class TestThreadLocal {
private static ThreadLocal<Integer> threadLocal=new ThreadLocal<Integer>();
// private static ThreadLocal threadLocal=new ThreadLocal(){
//
// @Override
// protected Integer initialValue() {
// return 0;
// }
// };
public static void main(String[] args) {
Thread t1=new Thread(new Runnable() {
@Override
public void run() {
System.out.println(threadLocal.get());
}
});
Thread t2=new Thread(new Runnable() {
@Override
public void run() {
threadLocal.set(3);
System.out.println("t2:"+threadLocal.get());
}
});
t1.start();
t2.start();
System.out.println(threadLocal.get());
}
}

如果需要设置默认值的话,可以实现initialValue方法。

典型场景1:我们知道SimpleDateFormat的对象如果多线程使用的话会有线程不安全的问题。具体代码如下:

public class TestThreadLocal {
public static ExecutorService executorService = Executors.newFixedThreadPool(16);
private static SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static void main(String[] args) throws InterruptedException {
for (int i=0;i<1000;i++){
executorService.submit(new Runnable() {
@Override
public void run(){
String format = simpleDateFormat.format(new Date());
try {
Date parse = simpleDateFormat.parse("2021-09-01 00:00:00");
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println(format);
}
});
}
Thread.sleep(3000);
executorService.shutdownNow();

}
}

运行结果如下:

可以看出,发生了异常。

方法1:我们可以改为每次都new一个新的SimpleDateFormat对象的话,这样再运行是没问题的。但是有些资源浪费。

方法2:使用ThreadLocal来解决。假设线程池里共16个线程,那我们总共16个SimpleDateFormat对象就可以应付所有的日期格式化的调用。

代码如下:

public class TestThreadLocal {
public static ExecutorService executorService = Executors.newFixedThreadPool(16);
private static ThreadLocal<SimpleDateFormat> threadLocal=new ThreadLocal<SimpleDateFormat>(){
@Override
protected SimpleDateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
};
private static SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static void main(String[] args) throws InterruptedException {
for (int i=0;i<1000;i++){
executorService.submit(new Runnable() {
@Override
public void run() {
String format = threadLocal.get().format(new Date());
try {
Date parse = threadLocal.get().parse("2021-09-01 00:00:00");
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println(format);
}
});
}
Thread.sleep(3000);
executorService.shutdownNow();

}
}

注意: 如果不使用线程池,线程结束,线程里的threadLocalMap也会被回收。但是如果使用线程池,线程池里面的线程会被复用,线程里的threadLocalMap不会被回收,就造成了内存泄漏。按照正确的使用方法应该是每次用完了remove,但是这样效率就很低。还不如方法1每次去new一个新的SimpleDateFormat对象。(但个人觉得其实还好,泄漏一点也没关系,不过threadlocal毕竟不是专门解决线程安全问题的,不推荐这么用)

正确使用方法

ThreadLocal 高级部分

ThreadLocal为什么会内存泄露?

内存泄漏(Memory Leak)是指程序中已动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。

试想:

一个线程对应一块工作内存,线程可以存储多个ThreadLocal。那么假设,开启1万个线程,每个线程创建1万个ThreadLocal,也就是每个线程维护1万个ThreadLocal小内存空间,而且当线程执行结束以后,假设这些ThreadLocal里的Entry还不会被回收,那么将很容易导致堆内存溢出。

怎么办?难道JVM就没有提供什么解决方案吗?

答案:

  1. JVM利用设置ThreadLocalMap的Key为弱引用,来避免内存泄露。
  2. JVM利用调用remove、get、set方法的时候,回收脏value值。

ThreadLocal的关系图如下所示:

Thread里面维护了一个ThreadLocalMap,这个map里面的key是弱引用的readLocal实例。value是我们设置进去的值。当把treadLocal实例对象置为null后,没有任何强引用指向threadLocal实例,所以theadLocal将会被gc回收。但是我们的value不会被回收,因为存在一个thread连接过来的强引用。只有当thread结束后,强引用断开,map、value等将全部被回收。

如下图:

但是很多时候我们使用线程池,为了复用线程,thread生命周期没有结束,所以无法回收,造成内存泄漏。

来源:今日头条内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯