当前位置: 首页 > article >正文

ThreadLocal源码详解

目录

Thread、ThreadLocalMap 、ThreadLocal关系

ThreadLocal中的get、Set方法

ThreadLocal 内存泄露问题


Thread、ThreadLocalMap 、ThreadLocal关系

从源码可以看出:Thread类中有成员变量ThreadLocalMap,ThreadLocalMap类中有成员变量Entry[]数组,每个Entry对象的key是ThreadLocal实例,Value放的是每个ThreadLocal绑定的对象,示意图如下:

ThreadLocal中的get、Set方法

get方法源码解析:获取当前线程的ThreadLocalMap,在ThreadLocalMap的Entry数组中获取Entry对象(通过threadlocal的hashcode),最后获取Entry对象的value就是get方法的返回值

set方法源码解析:获取当前线程的ThreadLocalMap,找到ThreadLocalMap对应的Entry数组,根据当前ThreadLocal对象的hashCode找到插入Entry数组的位置,Entry对象的key就是当前ThreadLocal对象,Value就是ThreadLocal绑定的对象。

ThreadLocal 内存泄露问题

内存泄漏:如果不会被使用的对象或者变量占用的内存不能被回收,就是内存泄漏。如果泄漏的数据量足够大,可能会引起内存溢出,导致程序异常结束。

在 ThreadLocalMap 中的 Entry 的 key 是对 ThreadLocal 的 WeakReference 弱引用,而 value 是强引用。当 ThreadLocalMap 的 ThreadLocal 对象只被弱引用,GC 发生时该对象会被清理,此时 key 为 null,但 value 为强引用不会被清理。此时 value 将访问不到也不被清理掉就可能会导致内存泄漏。

从示意图可以看出,红色实线部分是强引用,黑色虚线部分是弱引用,当gc时,如果ThreadLocal没有被外部强引用,会将ThreadLocal对象回收掉,会导致ThreadLocalMap的Key为null,key=null对应的value,被线程对象Thread强引用,如果线程迟迟不结束,那些value的这块内存永远无法访问,也无法回收,发送了内存泄漏。

案例演示ThreadLocal内存泄漏:

package com.gingko.threadlocal;

import com.gingko.entity.Student;

public class TransferParam {

    //线程中放入student信息,整个线程链路上都可以获取student信息
    private static ThreadLocal<Student> studentThreadLocal = new ThreadLocal<>();

    public static void main(String[] args) {
        TransferParam transferParam = new TransferParam();
        transferParam.setParam();
        studentThreadLocal = null;
        System.gc();
        Thread thread = Thread.currentThread();
        System.out.println("");
    }
    public void setParam() {
        Student student = new Student("1","张三",18,"001");
        studentThreadLocal.set(student);
        new ServiceA().getParam();
    }

    class ServiceA {
        public void getParam() {
            Student student = studentThreadLocal.get();
            System.out.println("ServiceA:" + student);
            new ServiceB().getParam();
        }
    }
    class ServiceB {
        public void getParam() {
            Student student = studentThreadLocal.get();
            System.out.println("ServiceB:" + student);
            //线程链路的最后删除threadlocal信息,防止发生内存泄露
            //studentThreadLocal.remove();
        }
    }
}

 程序debug效果:

从程序看出,如果线程迟迟没有结束,而threadlocal已经没有引用,此时gc时,value=student的信息仍然存在且访问不到,这段时间发生了内存泄漏,只有线程结束后,引用关系断开,这些内存对象才能被回收。解开注释:studentThreadLocal.remove(); student信息就从Entry中清除了。

防止内存泄漏的方法:使用完ThreadLocal都调用它的remove()方法清除数据。


http://www.kler.cn/news/363483.html

相关文章:

  • Android 两种方式实现类似水波扩散效果
  • win10中mysql数据库binlog恢复
  • 谷歌新安装包文件形式 .aab 在UE4中的打包原理
  • Redis底层和缓存雪崩,击穿,穿透
  • 网站前端登录加密方案调查
  • 类加载器介绍
  • 前言——25机械考研复试专业面试问题汇总 机械复试超全流程攻略 机械复试看这一个专栏就够用了!机械复试调剂英语自我介绍口语专业面试常见问题总结 机械保研面试
  • 实用的 Python 小脚本
  • 无线网络的几种认证与加密方式
  • 程序员职业生涯总结之设计自己的人生算法
  • 【github小问题】——push后报错error: src refspec master does not match any
  • 数据链中常见电磁干扰matlab仿真,对比噪声调频,线性调频,噪声,扫频,灵巧五种干扰模型
  • 基于Springboot相亲网站系统的设计与实现
  • C#第三讲:面向对象、类、对象、类成员【定义】
  • React Native 持久化数据
  • 502 错误码通常出现在什么场景?
  • C/C++语言基础--C++四大类型转换讲解
  • goland/phpstrom快捷键
  • 太速科技-217-A(B)-Base Camera link 转光纤传输双向模块
  • 后端接口接受的是文件流,前端怎么把一张图片地址转换成文件流?
  • 华为ENSP基础实验
  • 【电机应用】变频器控制——变频水泵、变频空调
  • VMware Workstation Pro 16 搭建 android-x86过程问题罗列
  • 【可看】On the Generalization of GAN Image Forensics
  • 实战OpenCV之兴趣点检测
  • Netty核心组件