ThreadLocal核心源码阅读

1. 概述

ThreadLocal为每个使用该变量的线程提供独立的变量副本,因此每一个线程都可以独立地改变自己的副本,而不会影响其他线程。

入门例子:

public class ThreadLocalStudy {

    static ThreadLocal<String> stringThreadLocal = new ThreadLocal<>();

    public static void main(String[] args) throws InterruptedException {
        new Thread(
                () -> {
                    stringThreadLocal.set("5");
                    System.out.println(stringThreadLocal.get());
                    test();
                }
        ).start();
        TimeUnit.SECONDS.sleep(10);
    }

    public static void test() {
        System.out.println(stringThreadLocal.get());
    }
}

在这里插入图片描述

2. 源码阅读

ThreadLocal.ThreadLocalMap threadLocals 是 Thread局部属性字段

public class Thread implements Runnable {
    ThreadLocal.ThreadLocalMap threadLocals = null;
    ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
}

ThreadLocal.ThreadLocalMap
key: ThreadLocal 弱引用 value: 对应的值

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;
private Entry[] table;
private int size = 0;
private int threshold; // Default to 0
private void setThreshold(int len) {
    threshold = len * 2 / 3;
}
private static int nextIndex(int i, int len) {
    return ((i + 1 < len) ? i + 1 : 0);
}
private static int prevIndex(int i, int len) {
    return ((i - 1 >= 0) ? i - 1 : len - 1);
}

ThreadLocal 常用方法源码阅读:

public void set(T value) {
    Thread t = Thread.currentThread();
    // 1. 获取当前线程的ThreadLocalMap
    ThreadLocalMap map = getMap(t);
    if (map != null)
        // 2.1 设置值 key:stringThreadLocal value: 对应的值
        map.set(this, value);
    else
        // 2.2 创建Map
        createMap(t, value);
}

ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
}

void createMap(Thread t, T firstValue) {
    // ThreadLocalMap key: stringThreadLocal value: 对应的值
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}

public T get() {
    Thread t = Thread.currentThread();
    // 1. 获取当前线程的threadLocals
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        // 2. 使用key stringThreadLocal 获取 Entry
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            // 返回结果
            return result;
        }
    }
    // threadLocals 设置value为null的键值对,并返回null
    return setInitialValue();
}

ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
}

// 移除当前线程的 threadLocals中 stringThreadLocal 的键值对
public void remove() {
    ThreadLocalMap m = getMap(Thread.currentThread());
     if (m != null)
         m.remove(this);
     }
}

3. ThreadLocalMap的key为什么用弱引用

当 线程中的 threadLocal 被GC回收,threadLocal在堆中只有弱引用指向,就可以被回收了,但是value不会被回收,所以还是会有内存泄漏的情况,所以代码运行完成要用 remove清除一下。
在这里插入图片描述

测试代码如下:

public class ThreadLocalStudy {

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i <= 100; i++) {
            System.out.println(i);
            TimeUnit.SECONDS.sleep(1);
            new Thread(
                    () -> {
                        ThreadLocal<byte[]> threadLocal = new ThreadLocal<>();
                        byte[] oneM = new byte[1024 * 1024];
                        threadLocal.set(oneM);
                        System.out.println(threadLocal.get().length);
                        // 切断threadLocal的强引用
                        threadLocal = null;

                        System.gc();

                        try {
                            TimeUnit.SECONDS.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
            ).start();

        }
        TimeUnit.MINUTES.sleep(100);
    }
}

堆大小 20m
在这里插入图片描述
运行截图:

在这里插入图片描述

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

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

相关文章

C语言:顺序表专题

目录 一、数据结构之顺序表/链表1.数据结构相关概念1.1什么是数据结构1.2为什么需要数据结构 二、顺序表1.顺序表的概念及结构2.顺序表分类3.动态顺序表的实现 一、数据结构之顺序表/链表 1.数据结构相关概念 1.1什么是数据结构 数据结构是由“数据”和“结构”两词组合而来…

医学图像处理 利用pytorch实现的可用于反传的Radon变换和逆变换

医学图像处理 利用pytorch实现的可用于反传的Radon变换和逆变换 前言代码实现思路实验结果 前言 Computed Tomography&#xff08;CT&#xff0c;计算机断层成像&#xff09;技术作为如今医学中重要的辅助诊断手段&#xff0c;也是医学图像研究的重要主题。如今&#xff0c;随…

Python-VBA函数基础知识-001

一、函数的定义&#xff1a; 函数(Function)是一段可重复使用的代码块&#xff0c;用于执行特定的任务或计算&#xff0c;并可以接受输入参数和返回输出结果。函数可以将复杂的问题分解为更小的子问题&#xff0c;提高代码的可读性和可维护性。 二、函数的组成&#xff1a; 在…

基于单片机电子指南针系统设计

**单片机设计介绍&#xff0c;基于单片机电子指南针系统设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机电子指南针系统设计概要主要涵盖了硬件设计、软件设计、磁场传感器选择、数据处理和显示等方面。以下是对该…

记某客户的一次无缝数据迁移

背景 客户需要将 Elasticsearch 集群无缝迁移到移动云&#xff0c;迁移过程要保证业务的最小停机时间。 实现方式 通过采用成熟的 INFINI 网关来进行数据的双写&#xff0c;在集群的切换恢复过程中来记录数据变更&#xff0c;待全量数据恢复之后再追平后面增量数据&#xff…

C++从入门到精通——类的作用域及类的实例化

类的作用域及类的实例化 前言一、类的作用域二、类的实例化引例类是对对象进行描述的示例 一个类可以实例化出多个对象示例 示例 前言 类的作用域是指类中定义的变量和方法的可见性和可访问性范围。在类的内部&#xff0c;所有成员&#xff08;包括属性和方法&#xff09;都具…

快速理解JS中的原型和原型链

快速理解JS中的原型和原型链 在我们学习JS的过程中&#xff0c;我们总会接触到一些词&#xff1a;“原型”&#xff0c;“原型链”。那么今天我就来带大家来学习学习原型和原型链的知识吧&#xff01; 在开始之前&#xff0c;我们明确一下我们接下来想要学习的目标&#xff1a…

【机器学习】K-means聚类算法:原理、应用与优化

一、引言 1、简述聚类分析的重要性及其在机器学习中的应用 聚类分析&#xff0c;作为机器学习领域中的一种无监督学习方法&#xff0c;在数据探索与知识发现过程中扮演着举足轻重的角色。它能够在没有先验知识或标签信息的情况下&#xff0c;通过挖掘数据中的内在结构和规律&a…

使用Springfox Swagger实现API自动生成单元测试

目录 第一步&#xff1a;在pom.xml中添加依赖 第二步&#xff1a;加入以下代码&#xff0c;并作出适当修改 第三步&#xff1a;在application.yaml中添加 第四步&#xff1a;添加注解 第五步&#xff1a;运行成功之后&#xff0c;访问相应网址 另外&#xff1a;还可以导出…

ES学习日记(七)-------Kibana安装和简易使用

前言 首先明确一点&#xff0c;Kibana是一个软件&#xff0c;不是插件。 Kibana 是一款开源的数据分析和可视化平台&#xff0c;它是 Elastic stack 成员之一&#xff0c;设计用于和Elasticsearch 协作。您可以使用 Kibana 对 Elasticsearch 索引中的数据进行搜索&#xff0c;…

python文件打包找不到文件路径

引用&#xff1a;【将Python代码打包成exe可执行文件】 https://www.bilibili.com/video/BV1P24y1o7FY/?p4&share_sourcecopy_web&vd_sourced5811f31a0635dfc69a182c7bf1adb8b 在代码中&#xff0c;我们想读取文件a&#xff0c;一般使用如下方法。 import osdir os…

Spring Boot Mockito (三)

Spring Boot Mockito (三) 这篇文章主要是讲解Spring boot 与 Mockito 集成测试。 前期项目配置及依赖可以查看 Spring Boot Mockito (二) - DataJpaTest Spring Boot Mockito (一) - WebMvcTest Tag("Integration") SpringBootTest // TestMethodOrder(MethodOr…

安科瑞直流电表在光伏储能行业中的应用-安科瑞黄安南

双碳”背景下&#xff0c;储能产业站上市场风口&#xff0c;全球储能市场需求迅猛爆发。作为储能产业链的中游环节&#xff0c;系统集成商上承设备提供商&#xff0c;下接储能系统业主&#xff0c;已经成为储能行业最受关注的“焦点”。对于储能系统集成商来说&#xff0c;技术…

【研发日记】白话解读UDS协议(一)——19 04读取快照服务

文章目录 前言 19服务 04子服务 19 04协议 快照存储设计 快照发送设计 功能验证 分析和应用 总结 前言 近期在一个嵌入式软件开发项目中&#xff0c;要按照UDS标准开发相关功能&#xff0c;期间在翻阅UDS标准时&#xff0c;周围同事都说很多地方晦涩难懂。所以利用晚上…

大创项目推荐 深度学习 大数据 股票预测系统 - python lstm

文章目录 0 前言1 课题意义1.1 股票预测主流方法 2 什么是LSTM2.1 循环神经网络2.1 LSTM诞生 2 如何用LSTM做股票预测2.1 算法构建流程2.2 部分代码 3 实现效果3.1 数据3.2 预测结果项目运行展示开发环境数据获取 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天…

【前端】CSS(引入方式+选择器+常用元素属性+盒模型+弹性布局)

文章目录 CSS一、什么是CSS二、语法规范三、引入方式1.内部样式表2.行内样式表3.外部样式 四、选择器1.选择器的种类1.基础选择器&#xff1a;单个选择器构成的1.标签选择器2.类选择器3.id 选择器4.通配符选择器 2.复合选择器1.后代选择器2.子选择器3.并集选择器4.伪类选择器 五…

一文教你配置 Tomcat 9.0.19 + Java 12.0.2,并启用 SSL——以 Windows Server 2019 平台为例

Tomcat 的运行依赖 JAVA 环境&#xff01;安装的时候会让你选择 JDK 所在路径。 Linux 下的安装教程已更新&#xff1a; 操作系统&#xff1a;Windows Server 2019 Datacenter JAVA 版本&#xff1a;12.0.2 Tomcat 版本&#xff1a;9.0.19 GeoServer 版本&#xff1a;2.23.2 …

【机器学习入门】使用YOLO模型进行物体检测

系列文章目录 第1章 专家系统 第2章 决策树 第3章 神经元和感知机 识别手写数字——感知机 第4章 线性回归 第5章 逻辑斯蒂回归和分类 第5章 支持向量机 第6章 人工神经网络(一) 第6章 人工神经网络(二) 卷积和池化 第6章 使用pytorch进行手写数字识别 文章目录 系列文章目录前…

LeetCode-51. N 皇后【数组 回溯】

LeetCode-51. N 皇后【数组 回溯】 题目描述&#xff1a;解题思路一&#xff1a;回溯&#xff0c; 回溯三部曲。验证是否合法只需要检查:1.正上方&#xff1b;2. 左上方&#xff1b;3.右上方。因为是从上到下&#xff0c;从左到右遍历的&#xff0c;下方不可能有皇后。解题思路…

计算机网络基础(一)

目录 一.互联网和因特网 二.因特网的发展历程 三.因特网的功能 3.1边缘部分 3.1.1&#xff1a;客户服务器方式&#xff08;C/S方式&#xff09; 3.1.2&#xff1a;对等方式 3.2.核心部分 3.2.1&#xff1a;电路交换 3.2.2.报文交换 3.2.3&#xff1a;分组交换 四.计…