【Java并发】ThreadLocal的实现原理源码解析

news/2024/10/18 5:49:57/

文章目录

    • 1.ThreadLocal是什么?
    • 2.ThreadLocald实现原理&源码解析
    • 3.ThreadLocal-内存泄露问题

1.ThreadLocal是什么?

ThreadLocal 是 Java 中的一个线程局部变量类。它提供了一种在多线程环境下,为每个线程独立存储数据的机制。

并且:
ThreadLocal 通过为每个线程创建一个独立的副本来实现线程隔离。每个线程都可以独立地修改和访问自己的副本,而不会影响其他线程的副本。每个线程都可以像访问普通变量一样访问 ThreadLocal 对象,而不必担心线程安全问题。

2.ThreadLocald实现原理&源码解析

ThreadLocal本质来说就是一个·线程内部存储类·,从而让多个线程只操作自己内部的值,从而实现线程数据隔离

基本方法有:

  1. set(value) 设置值
  2. get() 获取值
  3. remove() 清除值

set(value) 设置值
首先获取当前线程,然后获取当前线程的 ThreadLocalMap 对象。如果 ThreadLocalMap 存在,就将当前 ThreadLocal 对象作为,将值 value 存储到其中;否则,创建一个新的 ThreadLocalMap,并将当前 ThreadLocal 对象和值 value 存储到其中。

/*** 设置线程局部变量的值。* @param value 要设置的值*/
public void set(T value) {// 获取当前线程Thread t = Thread.currentThread();// 获取当前线程的 ThreadLocalMap,用于存储线程局部变量ThreadLocalMap map = getMap(t);if (map != null)// 如果 ThreadLocalMap 存在,则将当前 ThreadLocal 对象作为键,将 value 作为值存储起来map.set(this, value);else// 如果 ThreadLocalMap 不存在,则创建一个新的 ThreadLocalMap,并将当前 ThreadLocal 对象和 value 存储到其中createMap(t, value);
}

get() 获取值

通过ThreadLocal 对象去取对应的value

首先,获取当前线程并获取其对应的 ThreadLocalMap 对象。如果 ThreadLocalMap 存在,则通过调用 getEntry(this) 方法获取当前 ThreadLocal 对象对应的条目。如果条目存在,则返回条目中存储的值。如果线程局部变量不存在,则调用 setInitialValue() 方法返回初始值。

/*** 获取线程局部变量的值。* @return 线程局部变量的值,如果不存在则返回初始值*/
public T get() {// 获取当前线程Thread t = Thread.currentThread();// 获取当前线程的 ThreadLocalMap,用于存储线程局部变量ThreadLocalMap map = getMap(t);if (map != null) {// 通过 ThreadLocalMap 获取对应的条目ThreadLocalMap.Entry e = map.getEntry(this);if (e != null) {// 如果条目存在,则返回条目中存储的值@SuppressWarnings("unchecked")T result = (T)e.value;return result;}}// 如果线程局部变量不存在,则返回初始值return setInitialValue();
}

remove() 清除值

根据ThreadLocal 删除对

     /*** 从当前线程的 ThreadLocalMap 中移除当前 ThreadLocal 对象对应的条目。*/
public void remove() {// 获取当前线程的 ThreadLocalMapThreadLocalMap m = getMap(Thread.currentThread());if (m != null) {// 如果 ThreadLocalMap 存在,则调用 remove(this) 方法移除当前 ThreadLocal 对象对应的条目m.remove(this);}
}

3.ThreadLocal-内存泄露问题

什么是内存泄漏
内存泄漏是指在程序中,不再使用的对象仍然被占用着内存无法被垃圾回收器回收释放,导致内存占用逐渐增加,最终可能导致内存耗尽性能下降。

Java对象中的四种引用类型:强引用软引用弱引用虚引用

强引用:最为普通的引用方式,表示一个对象处于有用且必须的状态,如果一个对象具有强引用,则GC并不会回收它。即便堆中内存不足了,宁可出现OOM,也不会对其进行回收

在这里插入图片描述

弱引用:表示一个对象处于可能有用且非必须的状态。在GC线程扫描内存区域时,一旦发现弱引用,就会回收到弱引用相关联的对象。对于弱引用的回收,无关内存区域是否足够,一旦发现则会被回收

在这里插入图片描述
出现内存泄漏的原因:

  1. 长期持有:如果在 ThreadLocal 中设置的值长时间持有,而没有进行及时清理和释放可能导致内存泄漏。(只要线程不结束,就一直存在)

  2. 线程结束不清理:如果在线程结束没有正确地清理 ThreadLocal,可能会导致内存泄漏。因为线程结束后,对应的 ThreadLocalMap 对象不会被垃圾回收,其中的 ThreadLocal 对象无法释放。

  3. 对象强引用:每一个Thread维护一个ThreadLocalMap,在ThreadLocalMap中的Entry对象继承了WeakReference。其中key为使用弱引用的ThreadLocal实例,value为线程变量的副本

在这里插入图片描述
解决办法就是:使用完ThreadLocal后主动 remove 释放 key,value


http://www.ppmy.cn/news/1023609.html

相关文章

【Windows系统】磁盘、Partition和Volume的联系与区别

1、磁盘 Disk,磁盘。 以下摘自微软 磁盘设备和分区 - Win32 apps | Microsoft Learn 硬盘由一组堆积的盘片组成,其中每个盘片的数据都以电磁方式存储在同心圆或 轨道中。 每个盘片都有两个头,一个在盘片的两侧,在磁盘旋转时读取…

Javascript进阶[面向对象编程]

作者:20岁爱吃必胜客(坤制作人),近十年开发经验, 跨域学习者,目前于海外某世界知名高校就读计算机相关专业。荣誉:阿里云博客专家认证、腾讯开发者社区优质创作者,在CTF省赛校赛多次取得好成绩。…

每日一学——IP地址和子网掩码

IP地址和子网掩码是网络中非常重要的概念。IP地址是用于标识和寻址网络中设备(如计算机、手机等)的唯一标识符。而子网掩码则用于划分网络中的子网。 IP地址是一个由32位二进制数组成的地址,通常以点分十进制的形式表示,如192.16…

ArcGIS Pro基础:【按顺序编号】工具实现属性字段的编号自动赋值

本次介绍一个字段的自动排序编号赋值工具,基于arcgis 的字段计算器工具也可以实现类似功能,但是需要自己写一段代码实现, 相对而言不是很方便。 如下所示,该工具就是【编辑】下的【属性】下的【按顺序编号】工具。 其操作方法是…

使用Java根据表名导出与导入Sql

前言 很粗糙啊,有很多可以优化的地方,而且也不安全,但是临时用还是OK的,我这个是公司里面的单机软件,不联网。 嗨!我是一名社交媒体增长黑客,很高兴能帮助您优化和丰富关于批量作业导出和导入…

【Essential C++课后练习】纯代码(更新中)

文章目录 第一章 C编程基础1.41.51.61.71.8 第二章 面向过程的编程风格2.12.22.32.42.52.6 第一章 C编程基础 1.4 /*********************************************************************说明:试着扩充这个程序的内容:(1)要求用户同时输…

Redis心跳检测

在命令传播阶段&#xff0c;从服务器默认会以每秒一次的频率&#xff0c;向主服务器发送命令&#xff1a; REPLCON FACK <rep1 ication_ offset>其中replication_offset是从服务器当前的复制偏移量。 发送REPLCONF ACK命令对于主从服务器有三个作用&#xff1a; 检测主…

机器学习笔记 - 基于C++的​​深度学习 二、实现卷积运算

一、卷积 卷积是信号处理领域的老朋友。最初的定义如下 在机器学习术语中: I(…)通常称为输入 K(…)作为内核,并且 F(…)作为给定K的I(x)的特征图。 虑多维离散域,我们可以将积分转换为以下求和 对于二维数字图像,我们可以将其重写为: <