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工作原理和内存泄漏的预防相关推荐

  1. 深入剖析ThreadLocal实现原理以及内存泄漏问题

    关于ThreadLocalMap<ThreadLocal, Object>弱引用问题: 当线程没有结束,但是ThreadLocal已经被回收,则可能导致线程中存在ThreadLocalMa ...

  2. JavaScript的工作原理:内存管理+如何处理4个常见的内存泄漏

    本篇译文,删减了原文中一些无关紧要的内容,可以让大家花更少的阅读时间. 原文地址:https://blog.sessionstack.com/how-javascript-works-memory-m ...

  3. c++ thread 内存泄漏_深入剖析ThreadLocal原理、内存泄漏及应用场景

    本文主要针对JDK1.8讲解 ThreadLocal作用 先看一个简单的示例,创建两个线程,第一个线程向ThreadLocal中写入数据,第二个线程等待第一个线程完成从ThreadLocal中读取数据 ...

  4. ThreadLocal到底有没有内存泄漏?

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 1. 前言 ThreadLocal 也是一个使用频率较高 ...

  5. ThreadLocal基本使用和内存泄漏分析

    ThreadLocal基础部分 ThreadLoal的作用 保存线程的独立变量,即每个线程维护一份.这种变量在线程的生命周期内起作用,减少同一个线程内多个函数之间公共变量传递麻烦. 使用场景 需要给不 ...

  6. ThreadLocal到底有没有内存泄漏?从源码角度来剖析一波

    1. 前言 ThreadLocal 也是一个使用频率较高的类,在框架中也经常见到,比如 Spring. 有关 ThreadLocal 源码分析的文章不少,其中有个问题常被提及:ThreadLocal ...

  7. Java Review - 线程池中使用ThreadLocal不当导致的内存泄漏案例源码分析

    文章目录 概述 Why 内存泄露 ? 在线程池中使用ThreadLocal导致的内存泄漏 概述 ThreadLocal的基本使用我们就不赘述了,可以参考 每日一博 - ThreadLocal VS I ...

  8. 关于Android应用程序内存泄漏 你需要知道的一切

    关于Android应用程序内存泄漏 你需要知道的一切 原文:https://blog.aritraroy.in/everything-you-need-to-know-about-memory-lea ...

  9. 深入分析 ThreadLocal 内存泄漏问题

    转载自 http://www.importnew.com/22039.html ThreadLocal 的作用是提供线程内的局部变量,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数或者组件 ...

最新文章

  1. 【Python】深度学习中将数据按比例随机分成随机 训练集 和 测试集的python脚本
  2. php微信公众号获取天气预报,【微信公众平台开发】封装获取天气预报功能
  3. php mysql 白屏_apache+php+mysql的白屏问题
  4. 【uoj#94】【集训队互测2015】胡策的统计(集合幂级数)
  5. jscript换行等特殊字符
  6. 自动给 Asp.Net Core Api 增加 ApiVersionNeutral
  7. 主机文件复制到Ubuntu系统中
  8. springmvc重定向到另一个项目_springmvc怎么重定向,从一个controller跳到另外一个controller...
  9. 技术人必读:如何让自己成长为IT项目管理者
  10. Linux 命令(61)—— ldd 命令
  11. office系统构架
  12. 动态规划 —— 求解二项式系数
  13. 用JNDI连接数据库
  14. 关于学习Swift的一些感受
  15. python打字案例,Python 小案例 打字练习
  16. 棉猴论坛VIP之驱动基础系列教程 视频教程
  17. Kali-DDoS工具集合
  18. C++核心准则边译边学-I.4 接口类型应该精准且严格
  19. 服务化治理脚本:show-busiest-java-threads。
  20. ROSCon 2016视频和幻灯片发布 ROS机器人操作系统重要参考资料

热门文章

  1. Java多线程---线程通信(wait,notifyAll,生产者消费者经典范式,owner wait set,自定义显式锁BooleanLock)
  2. 算法题存档20190206
  3. jvm面试 -- 谈谈ClassLoader ,ClassLoader的双亲委派机制 , loadClass和forName的区别
  4. 第三部分 虚拟机执行子系统
  5. async/await和Promise区别
  6. CentOS 7 启动与切换图形界面
  7. linux curl
  8. 日结问题解决思路和方式
  9. virtio、vhost和vhost-user比较
  10. 整洁架构之道--三种经典的编程范式