返回顶部
首页 > 资讯 > 后端开发 > PHP编程 >java中ThreadLocal的基本原理
  • 685
分享到

java中ThreadLocal的基本原理

JavaThreadLocal基本原理JavaThreadLocal 2015-05-05 00:05:35 685人浏览
摘要

目录基本流程ThreadLoalMap数据结构Hash冲突及解决ThreadLocal内存泄露内存引用链路引用类型为什么使用弱引用而不是强引用泄露原因分析ThreadLocal应用场景源码实现一个线程内可以存多个ThreadLocal对象,存储的位置位于Thr

目录
  • 基本流程
  • ThreadLoalMap数据结构
    • Hash冲突及解决
  • ThreadLocal内存泄露
    • 内存引用链路
    • 引用类型
  • 为什么使用弱引用而不是强引用?
    • 泄露原因分析
      • ThreadLocal应用场景

        源码实现

        一个线程内可以存多个ThreadLocal对象,存储的位置位于Thread的ThreadLocal.ThreadLocalMap变量,在Thread中有如下变量:

        
        
        ThreadLocal.ThreadLocalMap threadLocals = null;

        ThreadLocalMap是由ThreadLocal维护的静态内部类,正如代码中注解所说这个变量是由ThreadLocal维护的。

        基本流程

        在这里插入图片描述

        ThreadLoalMap数据结构

        ThreadLoalMap是ThreadLocal中的一个静态内部类,类似HashMap的数据结构,但并没有实现Map接口。

        
        static class ThreadLocalMap {
         
            static class Entry extends WeakReference<ThreadLocal<?>> {
                
                Object value;
         
                Entry(ThreadLocal<?> k, Object v) {
                    super(k);
                    value = v;
                }
            }
         
            private static final int INITIAL_CAPACITY = 16;
         
            // ...
        }

        ThreadLoalMap中初始化了一个大小16的Entry数组,Entry对象用来保存每一个key-value键值对。通过上面的set方法,我们已经知道其中的key永远都是ThreadLocal对象。

        在这里插入图片描述

        Hash冲突及解决

        Entry在table中存储位置是通过hashcode算法获得。
        在向ThreadLocalMap中的Entry数值存储Entry对象时,会根据ThreadLocal对象的hash值,定位到table中的位置i。分三种情况:

        • 如果当前位置为空的,直接将Entry存放在对应位置;
        • 如果位置i已经有值且这个Entry对象的key正好是即将设置的key,那么重新设置Entry中的value;
        • 如果位置i的Entry对象和即将设置的key没关系,则寻找一个空位置;

        计算hash值便会有hash冲突出现,常见的解决方法有:再哈希法、开放地址法、建立公共溢出区、链式地址法等。

        上面的流程可以看出这里采用的是开放地址方法,如果当前位置有值,就继续寻找下一个位置,注意table[len-1]的下一个位置是table[0],就像是一个环形数组,所以也叫闭散列法。 如果一直都找不到空位置就会出现死循环,发生内存溢出。当然有扩容机制,一般不会找不到空位置的。

        ThreadLocal内存泄露

        内存引用链路

        根据前面对ThreadLocal的分析,得知每个Thread维护一个ThreadLocalMap,它key是ThreadLocal实例本身,value是业务需要存储的Object。也就是说ThreadLocal本身并不存储值,它只是作为一个key来让线程从ThreadLocalMap获取value。

        ThreadLocalMap是使用ThreadLocal的弱引用作为Key的,弱引用的对象在GC时会被回收。因此使用了ThreadLocal后,引用链如图所示:(其中虚线表示弱引用。)

        在这里插入图片描述

        引用类型

        强引用:java默认的引用类型,例如 Object a = new Object();其中 a 为强引用,new Object()为一个具体的对象。一个对象从根路径能找到强引用指向它,JVM虚拟机就不会回收。

        软引用(SoftReference):进行年轻代的垃圾回收不会触发SoftReference所指向对象的回收;但如果触发Full GC,那SoftReference所指向的对象将被回收。备注:是除了软引用之外没有其他强引用引用的情况下。

        弱引用(WeakReference) :如果对象除了有弱引用指向它后没有其他强引用关联它,当进行年轻代垃圾回收时,该引用指向的对象就会被垃圾回收器回收。

        虚引用(PhantomeReference) :该引用指向的对象,无法对垃圾收集器收集对象时产生任何影响,但在执行垃圾回收后垃圾收集器会通过注册在PhantomeReference上的队列来通知应用程序对象被回收。

        为什么使用弱引用而不是强引用?

        问题1:从表面上看内存泄漏的根源在于使用了弱引用,但为什么jdk采用了弱引用的实现而不是强引用呢?

        答案是:弱引用反而是为了解决内存存储问题而专门使用的。

        问题2:如果应用程序觉得ThreadLocal对象的使命完成,将threadLocal ref 设置为null,如果Entry中引用ThreadLocald对象的引用类型设置为强引用的话,会发生什么问题?

        答案是:ThreadLocal对象会无法被垃圾回收器回收,因为从thread对象出发,有强引用指向ThreadLocal的object。此时会违背用户的初衷,造成所谓的内存泄露。

        我们先来假设一下,如果key使用强引用,那么在其他持有ThreadLocal引用的对象都回收了,但ThreadLocalMap依旧持有ThreadLocal的强引用,这就导致ThreadLocal不会被回收,从而导致Entry内存泄露。

        对照一下,弱引用的情况。持有ThreadLocal引用的对象都回收了,ThreadLocalMap持有的是ThreadLocal的弱引用,会被自动回收。只不过对应的value值,需要在下次调用set/get/remove方法时会被清除。

        泄露原因分析

        当Thread执行完会被销毁,Thread.threadLocals指向的ThreadLocalMap实例也随之变为垃圾,它里面存放的Entity也会被回收。这种情况是不会发生内存泄漏的。

        发生内存泄露的场景一般存在于线程池的情况下。 此时,Thread生命周期比较长(存在循环使用),threadLocals引用一直存在,当其存放的ThreadLocal被回收(弱引用生命周期比较短)后,对应的Entity就成了key为null的实例,但value值不会被回收。 如果此Entity一直不被get()、set()、remove(),就一直不会被回收,也就发生了内存泄漏。

        所以,通常在使用完ThreadLocal后需要调用remove()方法进行内存的清除。

        接下来我们再延伸一下,想再来谈谈网络上关于ThreadLocalMap中存储大量Entry对象导致的内存“泄露”问题?

        网络观点:在使用ThreadLocal中set方法与remove方法需要成对执行,需要没有执行remove方法会造成内存泄露?甚至造成内存溢出?

        我的观点:当然能成对使用当然更好,但在实际情况中,其实不调用remove方法也不太容易造成内存溢出,因为从存储结构来看,除非创建海量线程,并且这些线程都不释放,导致大量线程内部持有的ThreadLocalMap中对象一直不会释放,但一个线程所持有的Entry对象个数不多,取决于关联的ThreadLocal对象个数,故我们需要的关注点而不是remove方法,而是防止线程资源泄露。

        ThreadLocal应用场景

        • 线程间数据隔离,各线程的ThreadLocal互不影响;
        • 方便同一个线程使用某一对象,避免不必要的参数传递;
        • 全链路追踪中的traceId或者流程引擎中上下文的传递一般采用ThreadLocal;
        • spring事务管理器采用了ThreadLocal;
        • Spring mvc的RequestContextHolder的实现使用了ThreadLocal;

        到此这篇关于ThreadLocal的基本原理的文章就介绍到这了,更多相关ThreadLocal原理内容请搜索编程界以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程界!

        --结束END--

        本文标题: java中ThreadLocal的基本原理

        本文链接: https://www.lsjlt.com/news/79.html(转载时请注明来源链接)

        有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

        猜你喜欢
        • flink基本原理
          一、简介开源流式处理系统在不断地发展,从一开始只关注低延迟指标到现在兼顾延迟、吞吐与结果准确性,在发展过程中解决了很多问题,编程API的易用性也在不断地提高。本文介绍一下 Flink 中的核心概念,这些概念是学习与使用 Flink 十分重要的基础知识,在后续开 ...
          365
          2023-04-02
          flink基本原理
        • 爬虫的基本原理
          爬虫是什么?如果我们把互联网比作一张大的蜘蛛网,数据便是存放于蜘蛛网的各个节点,而爬虫就是一只小蜘蛛,沿着网络抓取自己的猎物(数据)爬虫指的是:向网站发起请求,获取资源后分析并提取有用数据的程序;从技术层面来说就是 通过程序模拟浏览器请求站 ...
          381
          2023-04-02
          爬虫 基本原理
        • Mysql索引基本原理
          1.Mysql表空间、段、区、页     在讲索引的概念之前我们先说一下mysql中段区页的概念。     表空间是Mysql数据库存储的最高层,默认情况下InnoDB引擎只有一个表空间,所有的数据都是存放在这个表空间内。     在表空间下数据是以段区页的形 ...
          367
          2023-04-02
          Mysql索引基本原理
        • Python爬虫基本原理
          看崔庆才爬虫教程视频做的笔记。1.什么是爬虫?请求网站并提取数据的自动化程序。2.爬虫的基本流程发送请求:通过HTTP库向目标站点发起请求,即发送一个Request,请求可以包含额外的headers等信息,等待服务器响应。获取响应内容:如果 ...
          413
          2023-04-02
          爬虫 基本原理 Python
        • 浅谈SpringSecurity基本原理
          今天带大家了解一下SpringSecurity的基本原理,文中有非常详细的代码示例,对正在学习java的小伙伴们有很好地帮助,需要的朋友可以参考下 ...
          184
          2023-04-02
          SpringSecurity原理 Spring底层原理
        • MySQL分页的基本原理
          这篇文章主要介绍“MySQL分页的基本原理”,在日常操作中,相信很多人在MySQL分页的基本原理问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”MySQL分页的基本原理”的疑惑有所帮助!接下来,请跟着小编一起来 ...
          949
          2023-04-02
          mysql
        • GoldenGate的基本原理介绍
          本篇内容介绍了“GoldenGate的基本原理介绍”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!什么是GoldenGate官方定义:Orac ...
          436
          2023-04-02
          goldengate
        • 说MGR - MGR的基本原理
          状态机复制MGR本质上一个状态机复制的集群。在状态机复制的架构中,数据库被当做一个状态机。每一次写操作都会导致数据库的状态变化。为了创建一个高可用的数据库集群,有一个组件,即事务分发器,将这些操作按照同样的顺序发送到多个初始状态一致的数据库 ...
          859
          2023-04-02
          状态机 分布式的状态机 gr
        • jQuery的基本原理是什么
          这篇文章主要介绍“jQuery的基本原理是什么”,在日常操作中,相信很多人在jQuery的基本原理是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”jQuery的基本原理是什么”的疑惑有所帮助!接下来,请跟 ...
          141
          2023-04-02
          jquery
        • Java基础元注解基本原理示例详解
          这篇文章主要为大家介绍了Java基础元注解基本原理示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪 ...
          507
          2023-04-02
          Java 元注解 Java 基础原理
        • Java SpringSecurity入门案例与基本原理详解
          这篇文章主要介绍了java中Spring Security的实例详解的相关资料,spring security是一个多方面的安全认证框架,提供了基于JavaEE规范的完整的安全认证解决方案,需要的朋友可以参考下 ...
          914
          2023-04-02
          JavaSpring SpringSecurity
        • sql注入基本原理是什么
          这篇文章主要介绍了sql注入基本原理是什么,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。SQL注入基本原理WEB技术发展日新月异,但是徒手拼SQL的传统手艺还是受相当多的开发 ...
          1049
          2023-04-02
          sql注入
        • PHP伪协议基本原理介绍
          这篇文章主要介绍了PHP伪协议,php中有很多封装协议,最常见的如file协议,php协议,data协议,zip和phar协议等等 ...
          499
          2023-04-02
          PHP伪协议 PHP伪协议原理
        • Golang template 包基本原理分析
          目录template 概述解析流程Parse阶段Execute阶段小结template 概述最近在做脚手架相关的内容, 研究了一下 Go 的 text/template 包, 接下来跟大家分享下 template 的基本原理.在 Gol ...
          513
          2023-04-02
          Golang template 包 Golang template
        • CSS中Hack的基本原理和实现方式
          本篇内容主要讲解“CSS中Hack的基本原理和实现方式”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“CSS中Hack的基本原理和实现方式”吧!CSS Hack的基本原理和实现方式由于不同的浏览器 ...
          288
          2023-04-02
          css
        • Oracle字符集的基本原理
          本篇内容主要讲解“Oracle字符集的基本原理”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Oracle字符集的基本原理”吧!一、三个概念:1. Oracle数据库 ...
          470
          2023-04-02
          oracle
        • 香港vps的基本原理是什么
          香港VPS技术是包括有虚拟化,容器等,每个VPS都能够分配一个独立的IP,独立的操作系统,将不同VPS进行不同的配置,用程序模拟出独占的体验来。是介于虚拟的主机与独立的主机两种间的服务器,与虚拟的主机一样采用的是虚拟的技术,有具有虚拟主机所 ...
          450
          2023-04-02
          vps 香港vps 香港vps原理
        • Java中JDBC连接池的基本原理及实现方式
          本文详细讲解了Java中JDBC连接池的基本原理及实现方式,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧 ...
          395
          2023-04-02
          Java使用JDBC连接池 JDBC连接池
        • 深入了解Golang中reflect反射基本原理
          反射是这样一种机制,它是可以让我们在程序运行时(runtime)访问、检测和修改对象本身状态或行为的一种能力。本文主要带大家来看看Golang中reflect反射基本原理,需要的可以参考一下 ...
          929
          2023-04-02
          Golang reflect反射原理 Golang reflect反射 Golang reflect
        • 腾讯云TDSQL基本原理-读写分离
          当处理大数据量读请求的压力大、要求高时,可以通过读写分离功能将读的压力分布到各个从节点上。TDSQL MySQL版 默认支持读写分离功能,架构中的每个从机都能支持只读能力,如果配置有多个从机,将由网关集群(TProxy)自动分配到低负载从机上,以支撑大型应用程 ...
          271
          2023-04-02
          腾讯云TDSQL基本原理-读写分离
        热门问答
        编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
        • 官方手机版

        • 微信公众号

        • 商务合作