【Java并发知识总结 | 第九篇】ThreadLocal总结

在这里插入图片描述

文章目录

  • 9.ThreadLocal总结
    • 9.1ThreadLocal是什么?
    • 9.2ThreadLocal的作用?
    • 9.3使用ThreadLocal
    • 9.4ThreadLocal原理
    • 9.5ThreadLocal问题:内存泄漏/溢出
    • 9.6为什么key要设计成弱引用?
    • 9.7ThreadLocal中的强弱引用关系
    • 9.8ThreadLocalMap怎么解决Hash冲突?

9.ThreadLocal总结

9.1ThreadLocal是什么?

  • ThreadLocal是 Java 中提供的一种用于实现线程局部变量的工具类。
  • 它允许每个线程都拥有自己的独立副本,从而实现线程隔离,用于解决多线程中共享对象的线程安全问题

9.2ThreadLocal的作用?

  • 作为数据副本,当某些数据是以线程为作用域并且不同线程有不同数据副本时,可以考虑 ThreadLocal。
  • 保存线程上下文信息,在任意需要的地方可以获取,避免显示传参。
  • 解决线程安全问题,避免某些情况需要考虑线程安全必须同步带来的性能损失。

9.3使用ThreadLocal

  • 创建ThreadLocal
  • 设置ThreadLocal的值
  • 获取 ThreadLocal 的值
  • 删除 ThreadLocal 的值
//创建一个ThreadLocal变量
public static ThreadLocal<String> localVariable = new ThreadLocal<>();

//设置ThreadLocal变量的值
localVariable.set("当前用户值");

//获取ThreadLocal变量的值
String value = localVariable.get();

//删除ThreadLocal变量的值
localVariable.remove();
  • 下图为使用ThreadLocal保存登录用户信息

image-20240428205326426

9.4ThreadLocal原理

  1. ThreadLocal 本身并不存储任何值,它只是作为一个映射,来映射线程的局部变量。
  2. 当一个线程调用 ThreadLocal 的 set 或 get 方法时,实际上是访问线程自己的 ThreadLocal.ThreadLocalMap
  3. ThreadLocalMap 是 ThreadLocal 的静态内部类,它内部维护了一个 Entry 数组,key 是 ThreadLocal 对象,value 是线程的局部变量本身

1、调用set()和get()的过程?

public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}
  • 调用 ThreadLocal.set()
    • 调用 getMap(Thread) --> 返回当前线程的 ThreadLocalMap < ThreadLocal, value >
    • map.set(this, value),this 是 ThreadLocal,value 为想要实现线程隔离的对象
  • 调用 get()
    • 调用getMap(Thread) --> 返回当前线程的 ThreadLocalMap<ThreadLocal, value>-->map.getEntry(this)
    • 返回value

2、ThreadLocal 的实现原理?

  • 实现原理 :每个线程维护一个 Mapkey 为 ThreadLocal 对象(当前对象),value 为想要实现线程隔离的对象

    • 当需要存线程隔离的对象时,通过 ThreadLocal 的 set 方法将对象存入 Map 中
    • 当需要取线程隔离的对象时,通过 ThreadLocal 的 get 方法从 Map 中取出对象。
    • Map 的大小由 ThreadLocal 对象的多少决定

    image-20240428210254618

9.5ThreadLocal问题:内存泄漏/溢出

  1. 通常情况下,随着线程 Thread 的结束,其内部的 ThreadLocalMap 也会被回收,从而避免了内存泄漏。
  2. 如果一个线程一直在运行,并且其 ThreadLocalMap 中的 Entry.value 一直指向某个强引用对象那么这个对象就不会被回收,从而导致内存泄漏
  3. 当 Entry 非常多时,可能就会引发更严重的内存溢出问题。

解决方案:

很简单,使用完 ThreadLocal 后,及时调用 remove() 方法释放内存空间。

try {
    
    threadLocal.set(value);
    // 执行业务操作
    
} finally {
    threadLocal.remove(); // 确保能够执行清理
}

remove() 方法会将当前线程的 ThreadLocalMap 中的所有 key 为 null 的 Entry 全部清除,这样就能避免内存泄漏问题。

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;
        }
    }
}

public void clear() {
    this.referent = null;
}

9.6为什么key要设计成弱引用?

弱引用的好处是,当内存不足的时候,JVM 会主动回收掉弱引用的对象。

  • 例子:

    WeakReference key = new WeakReference(new ThreadLocal());
    
  • key 是弱引用,new WeakReference(new ThreadLocal()) 是弱引用对象,当 JVM 进行垃圾回收时,如果发现了弱引用对象,就会将其回收

  • 一旦 key 被回收,ThreadLocalMap 在进行 set、get 的时候就会对 key 为 null 的 Entry 进行清理。

总结:在 ThreadLocal 被垃圾收集后,下一次访问 ThreadLocalMap 时,Java 会自动清理那些键为 null 的条目get(), set(), remove())等方法均会触发)

9.7ThreadLocal中的强弱引用关系

  • 强引用:new User(“张三”)

  • 弱引用:

    • userThreadLocal 是一个强引用,new ThreadLocal<>() 是一个强引用对象;
    • new User("张三") 是一个强引用对象。
    • 在 ThreadLocalMap 中,key = new ThreadLocal<>()是一个弱引用对象
      • 当 JVM 进行垃圾回收时,如果发现了弱引用对象,就会将其回收。
    ThreadLocal<User> userThreadLocal = new ThreadLocal<>();
    userThreadLocal.set(new User("张三"));
    

关系链:

  • ThreadLocal 强引用 -> ThreadLocal 对象。
  • 当前的Thread 强引用 -> ThreadLocalMap。
  • ThreadLocalMap[i] 强引用了 -> Entry。
  • Entry.key 弱引用 -> ThreadLocal 对象。(当执行remove等方法,垃圾回收器会回收key为null的键值对)
  • Entry.value 强引用 -> 线程的局部变量对象。

image-20240428214208438

引用类型被垃圾回收时间用途死亡时间
强引用从来不会对象的一般状态将强引用弱化,并gc后
软引用内存不足对象缓存内存不足,并gc后
弱引用垃圾回收对象缓存gc后
虚引用未知未知未知

9.8ThreadLocalMap怎么解决Hash冲突?

  1. ThreadLocalMap 没有使用链表,自然也不是用链地址法来解决冲突了
  2. 它用的是另外一种方式——开放定址法。开放定址法是什么意思呢?简单来说,就是这个坑被人占了,那就接着去找空着的坑。

在这里插入图片描述

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

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

相关文章

【并发编程实战】并发的编程引发的三个问题--可见性/原子性/顺序性

前言 硬件和软件的发展都是相互的&#xff0c;硬件的发展&#xff0c;多核CPU,缓存&#xff0c;进程&#xff0c;线程&#xff0c;我们享受CPU带来的高性能的同时&#xff0c;必定同时也伴随着风险。为了解决这些&#xff0c;则出现了一些理论和实践 问题 问题一 缓存导致的…

最佳WordPress外贸主题推荐(2024)

WordPress是一个非常受欢迎的建站平台&#xff0c;它具有易用性&#xff0c;并提供了许多功能强大的主题和插件。如果你计划建立一个外贸独立站商城&#xff0c;选择一个适合的WordPress外贸主题至关重要。以下是一些外贸主题应具备的特点&#xff1a; 1. 欧美风格&#xff1a…

python代码实现kmeans对鸢尾花聚类

导入第三方库和模型 from sklearn import datasets import numpy as np import matplotlib.pyplot as plt from sklearn.cluster import KMeans2、创建画图函数 def draw_result(train_x, labels, cents, title):n_clusters np.unique(labels).shape[0]#获取类别个数color …

美富特 | 邀您参加2024全国水科技大会暨技术装备成果展览会

王涛 四川美源环能科技有限公司 技术总监 报告题目&#xff1a;绿色智慧水岛如何助力工业园区污水及再生水资源化利用降碳增效 拥有十余年的环保行业从业经验&#xff0c;对各类前沿物化、生化及膜技术均有丰富的研发、设计及应用经验&#xff0c;先后参与多项重点核心技术…

spring cloud eureka 初始化报错(A bean with that name has already been defined)

报错内容 The bean ‘eurekaRegistration’, defined in class path resource [org/springframework/cloud/netflix/eureka/EurekaClientAutoConfiguration E u r e k a C l i e n t C o n f i g u r a t i o n . c l a s s ] , c o u l d n o t b e r e g i s t e r e d . A …

Unity 数字字符串逗号千分位

使用InputField时处理输入的数字型字符串千分位自动添加逗号&#xff0c;且自动保留两位有效数字 输入&#xff1a;123 输出&#xff1a;123.00 输入&#xff1a;12345 输出&#xff1a;12,345.00 代码非常简单 using UnityEngine; using TMPro;public class …

ssm088基于JAVA的汽车售票网站abo+vue

汽车售票网站的设计与实现 摘 要 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供服务。针对汽车售票信息管理混乱&#xff0c;出错率…

C++——string类的使用

1、string的构造 在 c plus plus 这个网站上可以查到相关的信息&#xff0c; (1)是无参构造函数(也是默认构造),就是一个空字符串 (2)是一个拷贝构造&#xff0c;传入一个参数构造字符串 (3)是一个有参构造&#xff0c;参数有点复杂&#xff0c;他有一个字符串&#xff0c;在…

强化SSH服务安全的最佳实践

SSH&#xff08;Secure Shell&#xff09;作为一种广泛应用于Linux和其他类Unix系统中的强大工具&#xff0c;为管理员提供了安全的远程登录和命令执行功能。在现今高度互联的网络环境中&#xff0c;确保SSH服务的安全性显得尤为重要。本文将详细阐述一系列SSH服务的最佳实践&a…

稳态视觉诱发电位 (SSVEP) 分类学习系列 (3) :3DCNN

稳态视觉诱发电位分类学习系列:3DCNN 0. 引言1. 主要贡献2. 提出的方法2.1 解码主要步骤2.2 网络具体结构2.3 迁移策略 3. 结果和讨论3.1 数据集1上的结果3.2 数据集2上的结果3.3 零填充 4. 总结欢迎来稿 论文地址&#xff1a;https://www.sciencedirect.com/science/article/a…

优秀博士学位论文分享:动态三维场景理解与重建

优秀博士学位论文代表了各学科领域博士研究生研究成果的最高水平&#xff0c;本公众号近期将推出“优秀博士学位论文分享”系列文章&#xff0c;对人工智能领域2023年优秀博士学位论文进行介绍和分享&#xff0c;方便广大读者了解人工智能领域最前沿的研究进展。 “博士学位论…

基于java+springboot+vue实现的在线考试系统(文末源码+Lw)204

摘 要 使用旧方法对在线考试系统的信息进行系统化管理已经不再让人们信赖了&#xff0c;把现在的网络信息技术运用在在线考试系统的管理上面可以解决许多信息管理上面的难题&#xff0c;比如处理数据时间很长&#xff0c;数据存在错误不能及时纠正等问题。这次开发的在线考试…

OpenAI发布GPT-4.0使用指南

大家好&#xff0c;ChatGPT 自诞生以来&#xff0c;凭借划时代的创新&#xff0c;被无数人一举送上生成式 AI 的神坛。在使用时&#xff0c;总是期望它能准确理解我们的意图&#xff0c;却时常发现其回答或创作并非百分之百贴合期待。这种落差可能源于我们对于模型性能的过高期…

百万人都在求的网络安全学习路线,渗透漏洞防御总结(附图)

前言 不折腾的网络安全&#xff0c;和咸鱼有什么区别 目录 二、 前言三 、同源策略 3.1 什么是同源策略 3.2 为什么需要同源策略四 、XSS 4.1 概览 4.2 介绍 4.3 防御五 、CSRF 5.1 概览 5.2 介绍 5.3 防御六、 SQL 注入七 、流量劫持 7.1 DNS 劫持 7.2 HTTP 劫持…

企业微信hook接口协议,ipad协议http,发送小程序

发送小程序 参数名必选类型说明uuid是String每个实例的唯一标识&#xff0c;根据uuid操作具体企业微信send_userid是long要发送的人或群idisRoom是bool是否是群消息 请求示例 {"uuid":"543ed7f3-6ec1-4db8339a140f7","send_userid":788130255…

「生存即赚」链接现实与游戏,打造3T平台生态

当前&#xff0c;在线角色扮演游戏&#xff08;RPG&#xff09;在区块链游戏市场中正迅速崛起&#xff0c;成为新宠。随着区块链技术的不断进步&#xff0c;众多游戏开发者纷纷将其游戏项目引入区块链领域&#xff0c;以利用这一新兴技术实现商业价值的最大化。在这一趋势中&am…

Android如何使用XML自定义属性

1、定义 在res/values文件下定义一个attrs.xml文件&#xff0c;代码如下: 2、使用 在布局中使用&#xff0c; 示例代码如下&#xff1a; 3、获取 最终来到这里&#xff1a;

异常处理Exception(二)

文章目录 1、自定义异常类1、定义消息类2、自定义异常类 2、调用3、测试总结 ABAP预定义的异常类在某些时候并不能精确地描述异常&#xff0c;此时就需要自定义异常类。 1、自定义异常类 1、定义消息类 2、自定义异常类 在Local Types中自定义异常类&#xff0c;当异常触发时…

开箱即用的使用体验!Alibaba Cloud Linux 的演进之旅

随着云计算的发展&#xff0c;越来越多的云上用户对操作系统提出了新的诉求。在 2023 龙蜥操作系统大会阿里云分论坛上&#xff0c;阿里云操作系统团队贾正华分享了 Alibaba Cloud Linux&#xff08;以下简称“Alinux”&#xff09;的发展历程及未来展望&#xff0c;介绍了 Ali…

unittest_parameterized批量测试测试用例

import unittest from parameterized import parameterizeddef add(x, y):return xy"""问题&#xff1a;如果有三组数据需要测试&#xff1f;[(1,1,2), (1,2,3), (0,3,3)] """def get_data():return [(1, 2, 3), (3, 0, 3), (2, 1, 3)]# 定义测试…