ThreadLocal工作原理和内存泄漏的预防
ThreadLocal是什么?
ThreadLocal是一个用于提供线程局部变量的一个工具类,用于保证线程安全,在他里面包含了一个ThreadLocalMap,真正的引用确是在Thread中,一般用private static加以修饰,
ThreadLocal的作用
threadlocal用于存取线程独享数据,提高访问效率。
ThreadLocal的底层源码
当我们要将一个Object放入对应的线程中时调用threadLocal.set()代码如下:
public void set(T value) {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);//每一个线程的内部(堆)其实都对应一个Map实例if (map != null)map.set(this, value);//存放ThreadLocal和当前值?只能放一个值?elsecreateMap(t, value);}
当我们想要得到每个线程的conn时:
public T get() {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null) {ThreadLocalMap.Entry e = map.getEntry(this);if (e != null)return (T)e.value;}return setInitialValue();}
从源码中可以知道,Map中的key为ThreadLocal,故每一个线程只能存放一个线程变量,多个会发生覆盖现象
public class testThreadlocal {static ThreadLocal<String> tl=new ThreadLocal<>();public static void main(String[] args) {new Thread(()->{try{TimeUnit.SECONDS.sleep(1);}catch(InterruptedException e){e.printStackTrace();}tl.set("456");System.out.println(tl.get());tl.set("789");System.out.println(tl.get());},"t1").start();new Thread(()->{try{TimeUnit.SECONDS.sleep(1);}catch(InterruptedException e){e.printStackTrace();}tl.set("123");},"t2").start();}
// static class Person{// String name="111";
// }}
关于内存泄漏
强引用-软引用-弱引用
强引用:普通的引用,强引用指向的对象不会被回收;
软引用:仅有软引用指向的对象,只有发生gc且内存不足,才会被回收;
弱引用:仅有弱引用指向的对象,只要发生gc就会被回收。
原因:
synchronized是用时间换空间、ThreadLocal是用空间换时间,为什么这么说?
因为synchronized操作数据,只需要在主存存一个变量即可,就阻塞等共享变量,而ThreadLocal是每个线程都创建一块小的堆工作内存。显然,印证了上面的说法。
一个线程对应一块工作内存,线程可以存储多个ThreadLocal。那么假设,开启1万个线程,每个线程创建1万个ThreadLocal,也就是每个线程维护1万个ThreadLocal小内存空间,而且当线程执行结束以后,假设这些ThreadLocal里的Entry还不会被回收,那么将很容易导致堆内存溢出。
怎么办?难道JVM就没有提供什么解决方案吗?
ThreadLocal当然有想到,所以他们把ThreadLocal里的Entry设置为弱引用,当垃圾回收的时候,回收ThreadLocal。
什么是弱引用?
Key使用强引用:也就是上述说的情况,引用的ThreadLocal的对象被回收了,ThreadLocal的引用ThreadLocalMap的Key为强引用并没有被回收,如果不手动回收的话,ThreadLocal将不会回收那么将导致内存泄漏。
Key使用弱引用:引用的ThreadLocal的对象被回收了,ThreadLocal的引用ThreadLocalMap的Key为弱引用,如果内存回收,那么将ThreadLocalMap的Key将会被回收,ThreadLocal也将被回收。value在ThreadLocalMap调用get、set、remove的时候就会被清除。
比较两种情况,我们可以发现:由于ThreadLocalMap的生命周期跟Thread一样长,如果都没有手动删除对应key,都会导致内存泄漏,但是使用弱引用可以多一层保障:弱引用ThreadLocal不会内存泄漏,对应的value在下一次ThreadLocalMap调用set,get,remove的时候会被清除。
那按你这么说,既然JVM有保障了,还有什么内存泄漏可言?
ThreadLocalMap使用ThreadLocal对象作为弱引用,当垃圾回收的时候,ThreadLocalMap中Key将会被回收,也就是将Key设置为null的Entry。如果线程迟迟无法结束,也就是ThreadLocal对象将一直不会回收,回顾到上面存在很多线程+TheradLocal,那么也将导致内存泄漏。
其实,在ThreadLocal中,当调用remove、get、set方法的时候,会清除为null的弱引用,也就是回收ThreadLocal。
总结:
JVM利用设置ThreadLocalMap的Key为弱引用,来避免内存泄露。
JVM利用调用remove、get、set方法的时候,回收弱引用。
当ThreadLocal存储很多Key为null的Entry的时候,而不再去调用remove、get、set方法,那么将导致内存泄漏。
当使用static ThreadLocal的时候,延长ThreadLocal的生命周期,那也可能导致内存泄漏。因为,static变量在类未加载的时候,它就已经加载,当线程结束的时候,static变量不一定会回收。那么,比起普通成员变量使用的时候才加载,static的生命周期加长将更容易导致内存泄漏危机。
https://www.jianshu.com/p/a1cd61fa22da
ThreadLocal工作原理和内存泄漏的预防相关推荐
- 深入剖析ThreadLocal实现原理以及内存泄漏问题
关于ThreadLocalMap<ThreadLocal, Object>弱引用问题: 当线程没有结束,但是ThreadLocal已经被回收,则可能导致线程中存在ThreadLocalMa ...
- JavaScript的工作原理:内存管理+如何处理4个常见的内存泄漏
本篇译文,删减了原文中一些无关紧要的内容,可以让大家花更少的阅读时间. 原文地址:https://blog.sessionstack.com/how-javascript-works-memory-m ...
- c++ thread 内存泄漏_深入剖析ThreadLocal原理、内存泄漏及应用场景
本文主要针对JDK1.8讲解 ThreadLocal作用 先看一个简单的示例,创建两个线程,第一个线程向ThreadLocal中写入数据,第二个线程等待第一个线程完成从ThreadLocal中读取数据 ...
- ThreadLocal到底有没有内存泄漏?
点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 1. 前言 ThreadLocal 也是一个使用频率较高 ...
- ThreadLocal基本使用和内存泄漏分析
ThreadLocal基础部分 ThreadLoal的作用 保存线程的独立变量,即每个线程维护一份.这种变量在线程的生命周期内起作用,减少同一个线程内多个函数之间公共变量传递麻烦. 使用场景 需要给不 ...
- ThreadLocal到底有没有内存泄漏?从源码角度来剖析一波
1. 前言 ThreadLocal 也是一个使用频率较高的类,在框架中也经常见到,比如 Spring. 有关 ThreadLocal 源码分析的文章不少,其中有个问题常被提及:ThreadLocal ...
- Java Review - 线程池中使用ThreadLocal不当导致的内存泄漏案例源码分析
文章目录 概述 Why 内存泄露 ? 在线程池中使用ThreadLocal导致的内存泄漏 概述 ThreadLocal的基本使用我们就不赘述了,可以参考 每日一博 - ThreadLocal VS I ...
- 关于Android应用程序内存泄漏 你需要知道的一切
关于Android应用程序内存泄漏 你需要知道的一切 原文:https://blog.aritraroy.in/everything-you-need-to-know-about-memory-lea ...
- 深入分析 ThreadLocal 内存泄漏问题
转载自 http://www.importnew.com/22039.html ThreadLocal 的作用是提供线程内的局部变量,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数或者组件 ...
最新文章
- 【Python】深度学习中将数据按比例随机分成随机 训练集 和 测试集的python脚本
- php微信公众号获取天气预报,【微信公众平台开发】封装获取天气预报功能
- php mysql 白屏_apache+php+mysql的白屏问题
- 【uoj#94】【集训队互测2015】胡策的统计(集合幂级数)
- jscript换行等特殊字符
- 自动给 Asp.Net Core Api 增加 ApiVersionNeutral
- 主机文件复制到Ubuntu系统中
- springmvc重定向到另一个项目_springmvc怎么重定向,从一个controller跳到另外一个controller...
- 技术人必读:如何让自己成长为IT项目管理者
- Linux 命令(61)—— ldd 命令
- office系统构架
- 动态规划 —— 求解二项式系数
- 用JNDI连接数据库
- 关于学习Swift的一些感受
- python打字案例,Python 小案例 打字练习
- 棉猴论坛VIP之驱动基础系列教程 视频教程
- Kali-DDoS工具集合
- C++核心准则边译边学-I.4 接口类型应该精准且严格
- 服务化治理脚本:show-busiest-java-threads。
- ROSCon 2016视频和幻灯片发布 ROS机器人操作系统重要参考资料