ThreadLocal学习

news2024/12/26 23:55:52

1、threadLocal图解

  java.lang.ThreadLocal类实现了线程的本地存储。

ThreadLocal的内部实现:

  • ThreadLocal的内部实现包括一个类似HashMap的对象,这里称之ThreadLocalMap。

  • ThreadLocalMap的key会持有对ThreadLocal实例的弱引用(Weak Reference),value会引用具体存储的对象实例。

【强引用】:

1、threalLocal对象指向threalLocalMap中的key .

2、线程对象 指向 堆中的 threalLocalMap。

【弱引用】:

1、threalLocalMap 的key为 threadLocal对象,即threadLocal对象 指向key为弱引用。

部分源码如下: 

// ThreadLocal类中的get()方法: 
	// 代码逻辑:
	// 1、通过当前线程对象,获取线程对象中的成员变量threadLocals 即threadLocalMap。
	// 2、拿到threadLocalMap后,根据当前threadLocal对象作为key,获取value值。
	// 3、如果threadLocalMap为空,进行初始化
	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();
    }

	// ThreadLocal类中的setInitialValue()方法: 设置ThreadLocalMap的初始化值。
	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;
    }
	// ThreadLocal类中的initialValue()方法:ThreadLocalMap初始value为null
	protected T initialValue() {
        return null;
    }
	// ThreadLocal类中的createMap方法: 初始化ThreadLocalMap,即线程的threadLocals对象初始化。
	void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }
	
	// ThreadLocalMap类的构造方法:存储用的是Entry数组。Entry的key为ThreadLocal对象。
	ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
        table = new Entry[INITIAL_CAPACITY];
        int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
        table[i] = new Entry(firstKey, firstValue);
        size = 1;
        setThreshold(INITIAL_CAPACITY);
    }

	// ThreadLocal类中的getMap方法:
	ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }
	// ThreadLocal类中的remove方法:
	public void remove() {
         ThreadLocalMap m = getMap(Thread.currentThread());
         if (m != null)
             m.remove(this);
     }
	// ThreadLocalMap类中的remove方法:
	private void remove(ThreadLocal<?> key) {
        Entry[] tab = table;
        int len = tab.length;
        int i = key.threadLocalHashCode & (len-1);
        for (Entry e = tab[i];
             e != null;
             e = tab[i = nextIndex(i, len)]) {
            if (e.get() == key) {
                e.clear();
                expungeStaleEntry(i);
                return;
            }
        }
    }

	// Thread类中的成员变量threadLocal即: 线程中的ThreadLocalMap
	ThreadLocal.ThreadLocalMap threadLocals = null;

 2、ThreadLocal原理

  • Thread类中一个成员变量,ThreadLocal.ThreadLocalMap threadLocals

  • ThreadLocal本身不存储数据,像是一个工具类,基于ThreadLocal去操作ThreadLocalMap

  • ThreadLocalMap本身就是基于Entrty[]实现的,因为一个线程被可以绑定多个ThreadLocalMap,这样一来,可能需要存储多个数据,所以采用Entrty[]的形式实现。

  • 每一个线程有自己独立的ThreadLocalMap, 再基于ThreadLocald对象本身作为key,对value进行存取。

  • ThreadLocalMap的key是一个弱引用。弱引用的特点:即便对象有弱引用,在GC时,也必须被回收。如果ThreadLocal对象为局部变量,即方法执行结束后,threadLocal对象强引用消失,如果key的引用是强引用,会导致threadLocal对象无法被回收如果threadLocal是静态成员变量,则不会存在这个问题

ThreadLocal内存泄露问题:

  • 如果threadLocal对象的引用丢失即:使用的threadLocal不是静态成员变量,而是局部变量),key因为弱引用被GC回收掉,如果同时线程还没有被回收,就会导致内存泄露,内存中的value无法被回收,同时也无法被获取到。

  • 解决方法:只需要在使用完毕threadLocal对象之后,及时的调用threadLocal.remove()方法,移除该threalLocal对象key的Entry即可。(说明:threadLocal.remove()是threadLocal对象的强引用,即在移除Entry前,threalLocal对象不会失效)

总结:

  • 线程中threadLocalMap(即threadLocals),是在第一次调用ThreadLocal的get或set方法时,才会创建。

  • 线程调用很深,但又不想传参时,可以使用threadLocals

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Perfectly Clear Workbench for Mac/Windows(智能图像清晰度处理软件)

Perfectly Clear Workbench是一款用于图像处理和修复的软件工具&#xff0c;它提供了一套强大的功能&#xff0c;旨在自动优化照片质量并消除常见的图像缺陷。这个工作台是Perfectly Clear家族的一部分&#xff0c;由Athentech Imaging开发和维护。 Perfectly Clear Workbench…

第一章:光纤通信概述

第一节&#xff1a;通信基本概念 1.1光纤通信基本概念 1.1.1光纤通信的概念 利用光导纤维传输广播信号的通信方式称为光纤通信。光波主要包括紫外线、可见光和红外线。光纤通信工作波长在近红外区&#xff0c;0.8um~1.8um的波长区&#xff0c;频率为167THz~375THz。光纤基础…

JWT跨域认证解决方案

JSON Web Token&#xff08;缩写 JWT&#xff09;是目前最流行的跨域认证解决方案&#xff0c;本文介绍它的原理和用法。 一、跨域认证的问题 互联网服务离不开用户认证 一般流程是&#xff1a; 1、用户向服务器发送用户名和密码 2、服务器验证通过后&#xff0c;在当前对话…

【SpringBoot】SpringBoot-Admin 服务监控 + 告警通知

简单介绍 Spring Boot Actuator 是 Spring Boot 自带的一个功能模块&#xff0c; 提供了一组已经开箱即用的生产环境下常用的特性和服务&#xff0c;比如应用程序的健康检查、信息暴露、度量收集、日志记录等。 在实际项目中&#xff0c;Actuator 可以帮助我们快速了解应用程序…

三维重建以及神经渲染中的学习(一)

三维重建以及神经渲染中的学习 公众号AI知识物语 本文内容为参加过去一次暑期课程学习时的笔记&#xff0c;浅浅记录下。 显示表征&#xff1a; 点云points&#xff1a;由一组离散三维点表征物体表面 推理速度快&#xff0c;容易获取 -离散表征&#xff0c;无拓扑关系 [Fa…

mysql的聚簇索引和非聚簇索引的区别

MySQL InnoDB存储引擎时&#xff0c;索引类型可分为聚簇索引和非聚簇索引&#xff0c;有时候也通俗的称为主键索引和普通索引。MyISAM的引擎只有非聚簇索引&#xff0c;所以MYSIAM的引擎在查询的时候非主键索引的时候特别快 接下来讨论一下几个问题&#xff1a; 什么是聚簇索…

linux搭建vsftpd服务使用filezilla连接服务

背景&#xff1a;支持使用filezilla上传文件到公司的服务机器上&#xff0c;所以搭建vsftpd支持filezilla进行上传 一、linux机器搭建vsftpd服务 1、先看看自己的机器属于什么发行版&#xff0c;不同的发行版命令不一样 我的是centos&#xff0c;其他发行版命令不一样&#xf…

架构训练营笔记:高可用设计

2-3高可用设计 高可用复杂度模型 分为计算高可用&#xff0c;存储高可用&#xff0c;高可用本质上需要冗余&#xff0c;这里是集群&#xff0c;没有单机。 计算高可用&#xff1a;分为任务分配与任务分解。 计算高可用对比之前的高性能&#xff0c;就是多了状态检测。 任务…

请求响应-实体参数的接受

实体参数的接受 简单实体对象&#xff1a;请求参数名与形参属性对象名相同&#xff0c;定义pojo接受即可&#xff0c;将数据封装到实体类中实体类代码如下&#xff1a; package com.example.POJO;public class User {private String name;private Integer age;public String g…

系统测试——postman的400错误

如果Headers中不勾选Host&#xff0c;调用接口就会报400 Bad Request错误。

Hystrix 断路器

文章目录 1 问题&#xff1a;服务雪崩2 概念3 服务降级3.1 概念&#xff1a;3.2 触发服务降级的情况&#xff1a;3.3 应用3.3.1 依赖3.3.2 解决的问题3.3.3 生产者&#xff1a;3.3.4 消费者&#xff1a;3.3.5 配置全局fallback方法3.3.6 解耦合 4 服务熔断4.1 概念&#xff1a;…

Shell的条件运算语句

目录 IF语句 单分支语句语法语法 多分支结构语法 CASE语句 语法 IF语句 单分支语句语法语法 #写法1 if 条件语句 then内容 fi#写法2 if 条件语句 ;then内容 fi编写一个内容警报器的例子 #!/bin/bash free_mem$(free -m | grep "Mem:" | tr -s " "…

kubernetes源码学习之kube-scheduler

kube-scheduler是kubernetes中的调度程序&#xff0c;负责从api server中获得待分发的pod列表&#xff0c;并为他们找到最合适运行的Node。 基于kubernetes 1.27 基本框架 下面是kubernetes官发给出的框架图&#xff0c;先对kubernetes pod调度的大致流程有一个认识 看一下有…

眼睛:来一场视觉盛宴《手拿把掐》css特效 —— 之听说过CSS【笑】

&#x1f637;&#x1f60a;&#x1f93a;&#x1f93a;&#x1f93a;前期回顾 打造极简风格动效 —— 5 分钟轻松实现惊艳、震撼人心的视觉效果_彩色之外的博客-CSDN博客 &#x1f601; css动画 —— 把你喜欢css动画嵌入到浏览器中_css做的动画效果怎么嵌入网页_彩色之外的…

window电脑修复网络不能正常

问题描述 问题的起点是我打开了OpenAPI公司的GPT&#xff0c;在回答的过程中响应很慢&#xff0c;然后自己开始尝试切换连接的服务器&#xff08;这里使用到了网络代理&#xff09;&#xff0c;最后自己做了一个操作是 代理软件的这个菜单里面的增强模式选项&#xff0c;结果…

Android爬坑指南————工信部又出新规!

工信部又出新规了&#xff01; 一、背景二、整改2.1 个人信息保护2.1.1 基本模式&#xff08;无权限、无个人信息获取模式&#xff09;腾讯视频网易云音乐 2.1.2 隐私政策内容 2.2 app权限调用2.2.1 应用内权限调用2.2.1.1 获取定位信息和生物特征识别信息2.2.1.2 其他权限 2.3…

渲染流程(上):HTML、CSS和JavaScript,是如何变成页面的?

在上一篇文章中我们介绍了导航相关的流程&#xff0c;那导航被提交后又会怎么样呢&#xff1f; 就进入了渲染阶段。这个阶段很重要&#xff0c;了解其相关流程能让你“看透”页面是如何工作的&#xff0c;有了这些知识&#xff0c;你可以解决一系列相关的问题&#xff0c;比如…

SVR算法简介及与其它回归算法的关系

目录 参考链接 有人可以帮助我理解支持向量回归技术和其他简单回归模型之间的主要区别是什么 支持向量回归找到一个线性函数&#xff0c;表示误差范围 (epsilon) 内的数据。也就是说&#xff0c;大多数点都可以在该边距内找到&#xff0c;如下图所示 这意味着 SVR 比大多数其…

TypeScript 学习笔记(一):基本类型、交叉类型、联合类型、类型断言

文章目录 一、常见类型1. 数组2. 布尔3. 数值4. 字符串5. object6. null 和 undefined7. symbol7.1 作为属性名7.2 属性名遍历7.3 静态方法&#xff1a;Symbol.for()和 Symbol.keyFor()7.4 内置 symbol 值7.4.1 Symbol.hasInstance7.4.2 Symbol.isConcatSpreadable7.4.3 Symbol…

Android 报错,闪退(错误)日志保存到手机内存中,以文本文件的形式保存

1.直接贴代码 import android.app.AlarmManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.os.Environment; import android.util.Log;import com.nuotu.atmBookClient.App;import java.io.File; i…