java中的ThreadLocal

ThreadLocal是线程局部变量,同一份变量在每一个线程中都保存一份副本,彼此线程之间操作互不影响

测试ThreadLocal

package com.alibaba.fescar.core.protocol.test;

public class TestThreadLocal {

    private static ThreadLocal<Integer> threadLocal = new ThreadLocal<>();

    public static void main(String[] args) {
        threadLocal.set(100);
        new Thread(()->{
            threadLocal.set(200);
            System.out.println("子线程"+threadLocal.get());
        }).start();

        System.out.println("主线程" + threadLocal.get());
    }
}

输出结果


如果子线程不设置ThreadLocal的值,那么get出来的是个什么值呢,将是个null值

 
ThreadLocal机制

实际上,真正起作用的是ThreadLocalMap,介绍下这个ThreadLocalMap

  • 这个Map的Key是ThreadLocal,vlaue是泛型值
  • ThreadLocalMap维护在Thread类中
  • ThreadLocalMap的创建是懒加载创建

下面是Thread类源码,可以看到Thread中维护了一个ThreadLocalMap 

看下ThreadLocal的set、get、remove

   public void set(T value) {
        // 获取当前线程
        Thread t = Thread.currentThread();
        // 获取当前线程的ThreadLocalMap
        ThreadLocalMap map = getMap(t);
     
        if (map != null)
        // 不为空,加入当前对象和value
            map.set(this, value);
        else
            // 否则创建ThreadLocalMap 传入当前线程和value
            createMap(t, value);
    }
 public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

    private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }

可以发现set和get方法都是懒加载的,当get或者set的时候才会去创建ThreadLocalMap 

    public void remove() {
         ThreadLocalMap m = getMap(Thread.currentThread());
         if (m != null)
             m.remove(this);
     }

InheritableThreadLocal是用于线程之间隔离的,但是InheritableThreadLocal可以使得子线程去自动拷贝来自父线程的副本数据 ,可以看到子线程拷贝了父线程的值

package com.alibaba.fescar.core.protocol.test;

public class TestThreadLocal {

    private static InheritableThreadLocal<Integer> threadLocal = new InheritableThreadLocal<>();

    public static void main(String[] args) {
        threadLocal.set(100);
        new Thread(()->{
            System.out.println("子线程"+threadLocal.get());
        }).start();

        System.out.println("主线程" + threadLocal.get());
    }
}

 输出结果


ThreadLocal与内存泄露 

内存泄漏

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

四种引用关系(强软弱虚)

强引用: 如 Object object= new Object(); 一个对象具有强引用,就不会被垃圾回收器回收。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止

引用:在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围进行第二次回收对象,用来描述一些还有用但并非必需的对象,使用SoftReference表示

弱引用:JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。在java中,用WeakReference来表示

虚引用:这个对象被收集器回收时收到一个系统通知,最弱的一中引用关系,不能通过虚引用来取得一个对象实例,用PhantomReference表示

GC判断该对象是否被回收

  • 引用计数: 对象被引用的时候,计数器加1,当计数器为0的时候代表对象可以被回收。

  • 可达性分析: 从GC Roots向下搜索,也就是从根对象往下搜索,经过的地方为引用链,如果对象不在引用链,则代表可被回收。

普遍采用可达性分析方法进行垃圾回收

 ThreadLocalMap

ThreadLocalMap是ThreadLocal的内部类,具体实现功能的也是它,可以看到ThreadLocal创建的ThreadLocalMap中的key是一个弱引用ThreadLocal对象

 

使用ThreadLocal过程中,如果ThreadLocal对象强引用断掉后,只剩弱引用,ThreadLocal对象会被回收

此时ThreadLocalMap中的key会变为null,而value没有被回收(value还是被当前线程强引用,只有当Thread线程退出后,value的强引用链才会断开)

同时又由于ThreadLocalMap是Thread中的成员属性,与Thread对象的生命周期是一样长,如果当前线程一直未被销毁(比如使用了线程池),又没有手动删除对应key,这样就会导致value内存泄漏,简而言之就是 key没了,value还在,value不能被回收就是内存泄漏

ThreadLocal的正确使用方法 

  • 每次使用完ThreadLocal都调用它的remove()方法清除数据
  • 将ThreadLocal变量定义成 private static,这样就一直存在ThreadLocal的强引用,也就能保证任何时候都能通过 ThreadLocal的弱引用访问到Entry的value值,进而清除掉 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/718355.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

泛微开发修炼之旅--17基于Ecology短信平台,实现后端自定义二开短信发送方案及代码示例

文章链接&#xff1a;17基于Ecology短信平台&#xff0c;实现后端自定义二开短信发送方案及代码示例

图像分割——U-Net论文介绍+代码(PyTorch)

0、概要 原理大致介绍了一下&#xff0c;后续会不断精进改的更加详细&#xff0c;然后就是代码可以对自己的数据集进行一个训练&#xff0c;还会不断完善&#xff0c;相应其他代码可以私信我。 一、论文内容总结 摘要&#xff1a;人们普遍认为&#xff0c;深度网络成功需要数…

全面了解三大 AI 绘画:Midjourney、Stable Diffusion、DALL·E 的区别和特点

大家好&#xff0c;我是设计师阿威 在当前&#xff0c;比较流行的 AI 绘画软件主要有三个&#xff0c;分别是&#xff1a;StabilityAI 公司的 Stable Diffusion&#xff0c;OpenAI 公司的 DALLE2&#xff0c;以及更为大众所熟知的&#xff0c;Leap Motion公司创始人 David Hol…

大前端 业务架构 插件库 设计模式 属性 线程

大前端 业务架构 插件库 适配模式之(多态)协议1对多 抽象工厂模式 观察者模式 外观模式 装饰模式之参考catagory 策略模式 属性

单片机建立自己的库文件(4)

文章目录 前言一、新建自己的外设文件夹1.新建外设文件夹&#xff0c;做项目好项目文件管理2.将之前写的.c .h 文件添加到文件夹中 二、在软件中添加项目 .c文件2.1 编译工程保证没问题2. 修改项目列表下的名称 三、在软件项目中添加 .h文件路径四、实际使用测试总结 前言 提示…

性能测试、负载测试、压力测试、稳定性测试简单区分【超详细】

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 性能测试是一个总称&#xff0c;可细分为性能测试、负载测试、压力测试、稳定性测试。 性能测试…

大量用户中招,远控木马已经潜伏各类在线会议平台

从 2023 年 12 月开始&#xff0c;研究人员发现有攻击者创建虚假 Skype、Google Meet 和 Zoom 网站来进行恶意软件传播。攻击者为安卓用户投递 SpyNote 远控木马&#xff0c;为 Windows 用户投递 NjRAT 和 DCRAT 远控木马。 攻击行动概述 攻击者在单个 IP 地址上部署了所有的虚…

LabVIEW电表改装与校准仿真系统

LabVIEW开发的电表改装与校准仿真实验平台不仅简化了传统的物理实验流程&#xff0c;而且通过虚拟仿真提高了实验的效率和安全性。该平台通过模拟电表改装与校准的各个步骤&#xff0c;允许学生在没有实际硬件的情况下完成实验&#xff0c;有效地结合了理论学习和实践操作。 项…

RAG未来的出路

总有人喊RAG已死,至少看目前不现实。 持这个观点的人,大多是Long context派,老实说,这派人绝大多数不甚理解长上下文的技术实现点,就觉得反正context越长,越牛B,有点饭圈化 ,当然我并不否认长上下文对提升理解力的一些帮助,就是没大家想的那么牛B而已(说个数据,达到…

Hazelcast 分布式缓存 在Seatunnel中的使用

1、背景 最近在调研seatunnel的时候&#xff0c;发现新版的seatunnel提供了一个web服务&#xff0c;可以用于图形化的创建数据同步任务&#xff0c;然后管理任务。这里面有个日志模块&#xff0c;可以查看任务的执行状态。其中有个取读数据条数和同步数据条数。很好奇这个数据…

Playwright鼠标悬浮元素定位方法

优点&#xff1a;你把鼠标点烂&#xff0c;把它从20楼丢下去&#xff0c;元素定位就在那&#xff0c;他不动&#xff0c;我说的偶像&#xff01; F12打开浏览器的调试页面 点击源代码Sources 右侧找到事件监听器断点&#xff08;Event Listener breakpoints&#xff09;&#…

Excel 常用技巧(六)

Microsoft Excel 是微软为 Windows、macOS、Android 和 iOS 开发的电子表格软件&#xff0c;可以用来制作电子表格、完成许多复杂的数据运算&#xff0c;进行数据的分析和预测&#xff0c;并且具有强大的制作图表的功能。由于 Excel 具有十分友好的人机界面和强大的计算功能&am…

分享:大数据信用报告查询哪家好?

在现代社会&#xff0c;个人信用报告对于个人信用评估、贷款申请以及金融服务的获取至关重要。随着大数据技术的发展&#xff0c;越来越多的平台提供了便捷的大数据信用报告查询服务。那么&#xff0c;到底应该选择哪家平台来查询大数据信用报告呢?以下是一些选择标准和推荐。…

标准立项 | 给水中试基地建设导则

结合近几年在已设计、建设和运维的不同规模的给水中试基地&#xff0c;凝练建设实践中所获得的实际经验和关键指标及参数&#xff0c;编制《给水中试基地建设导则》&#xff0c;以填补标准空白&#xff0c;统一建设标准。

LabVIEW共享变量

共享变量简介 LabVIEW​为​创建​分布​式​应用使用​共享​变量​可以简化​此类​应用的编程。​ 借助​共享​变量&#xff0c;​您​可以​在​同​一个​程序​框​图​的​不同​循环​之间​或者网络上​的​不同VI之间​共享​数据。与LabVIEW中的许多​其他数据​共…

GPT-4o的视觉识别能力,将绕过所有登陆的图形验证码

知识星球&#x1f517;除了包含技术干货&#xff1a;《Java代码审计》《Web安全》《应急响应》《护网资料库》《网安面试指南》还包含了安全中常见的售前护网案例、售前方案、ppt等&#xff0c;同时也有面向学生的网络安全面试、护网面试等。 我们来看一下市面上常见的图形验证…

在Qt编写的exe或者dll中设置版本号

1.背景 在别人编写的exe或者动态库中&#xff0c;通过右键–》属性–》详细信息中&#xff0c;通常都有版本信息&#xff1a; 那我们自己编译出来的Qt程序&#xff0c;如何设置这些版本号呢&#xff1f; 2.解决方案 参考【.pro文件中设置版本等信息】&#xff0c;只要在工…

50etf期权交易规则杠杆怎么计算?

今天带你了解50etf期权交易规则杠杆怎么计算&#xff1f;近年来&#xff0c;期权交易在股票市场中变得愈发流行&#xff0c;其中50ETF期权备受关注。作为一种金融衍生品&#xff0c;50ETF期权为投资者提供了更灵活的投资方式和更多的策略选择。 50etf期权交易规则杠杆怎么计算&…

介绍并改造一个作用于Anki笔记浏览器的插件

在Anki的笔记浏览器窗口中&#xff0c;作为主体部分的表格在对获取到的笔记进行排序时&#xff0c;最多只能有一个排序字段&#xff0c;在设定笔记的排序字段后&#xff0c;没法将表格中的笔记按其他字段进行排序。要满足这个需求&#xff0c;可以使用Advanced Browser插件&…

spring框架(SSM)

Spring Framework系统架构 Spring框架是一个开源的企业级Java应用程序框架&#xff0c;它为开发Java应用程序提供了一个全方位的解决方案。Spring的核心优势在于它的分层架构&#xff0c;这使得开发者可以灵活选择使用哪些模块而无需引入不需要的依赖。下面是Spring框架的一些关…