Java并发07之ThreadLocal

文章目录

  • 1 ThreadLocal原理
  • 2 内部结构
  • 3 内存泄露问题
  • 4 entry的key为什么被设计为弱引用

1 ThreadLocal原理

ThreadLocal类用来提供线程内部的局部变量。这种变量在多线程环境下访问时能保证各个线程的变量相对独立于其他线程内的变量。ThreadLocal实例通常来说都是private static类型的,用于关联线程和线程上下文。

ThreadLocal和synchronized对比:

  • synchronized采用以时间换空间的方式, 只提供了一份变量,让不同的线程排队访问。ThreadLocal采用以空间换时间的方式, 为每一个线程都提供了一份变量的副本,从而实现同时访问而相不干扰。
  • synchronized侧重于多个线程之间访问共享资源的同步。ThreadLocal侧重于多线程中让每个线程之间的数据相互隔离。

2 内部结构

JDK8中ThreadLocal的设计是:每个线程Thread维护一个ThreadLocalMap变量,这个Map的key是ThreadLocal实例本身,value才是真正要存储的值Object。

public void set(T value) {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);	// 通过当前线程去获取当前线程维护的ThreadLocalMap(Thread类的成员变量)if (map != null)		map.set(this, value);	// this是threadLocal对象else		createMap(t, value);
}

优点:这样设计之后每个Map存储的Entry数量就会变少。因为之前的存储数量由Thread的数量决定,现在是由ThreadLocal变量的数量决定。在实际运用当中,往往ThreadLocal变量的数量要远少于线程的数量。并且,当线程销毁之后,对应的ThreadLocalMap也会随之销毁,能减少内存的使用。

比如我们在一个线程中声明了两个ThreadLocal对象,Thread内部都是使用一个ThreadLocalMap存放数据的,ThreadLocalMap的key就是ThreadLocal对象,value就是ThreadLocal对象调用set方法设置的值。

3 内存泄露问题

在这里插入图片描述

当我们创建一个泛型为User的ThreadLocal对象并set进一个user后,会在虚拟机栈中存在三个对象引用,分别是Thread对象引用、ThreadLocal对象引用和user对象引用,这三个对象引用都指向堆内存的对象。其中thread对象有一个内部类对象ThreadLocalMap,这个map的每一个entry的key是threadlocal对象,value是user对象。因此对于一个entry对象,有ThreadLocalMap的强引用指向它;然后其中entry对象的key,是ThreadLocal对象的弱引;对于其中的value,是user对象的强引用。

static class Entry extends WeakReference<ThreadLocal<?>> {Object value;Entry(ThreadLocal<?> k, Object v) {super(k);value = v;}
}

所以,当ThreadLocal对象引用没了,那么ThreadLocal对象就没有被强引用指向了,在垃圾回收的时候,ThreadLocalMap的entry的key会被清理掉,但是value不会被清理掉。这样一来,ThreadLocalMap中就会出现key为null的Entry。

假如我们不做任何措施的话,value永远无法被GC回收,这个时候就可能会产生内存泄露。ThreadLocalMap 实现中已经考虑了这种情况,在调用set()、get()、remove()方法的时候,会清理掉key为null 的记录。使用完 ThreadLocal方法后最好再手动调用remove()方法。

4 entry的key为什么被设计为弱引用

因为ThreadlocalMap是和线程绑定在一起的,如果线程没有被销毁,即使我们已经不会再用某个ThreadLocal对象了,由于这个ThreadLocal对象对应的entry还存在,并且key如果是强引用的话,那么就会一直指向ThreadLocal对象,那么这个对象就一直不会被回收,于是就出现了内存泄漏。

为了避免这种情况,只要将key设置为弱引用,那么当发生GC的时候,就会自动将弱引用给清理掉。也就是说:如果ThreadLocal对象不再使用了,那么虚拟机栈中ThreadLocal对象的强引用就会去掉,那么就剩下entry中key的弱引用指向ThreadLocal对象了,很快这个ThreadLocal对象就会被GC回收掉了。

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

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

相关文章

python股票数据分析(Pandas)练习

需求&#xff1a; 使用pandas读取一个CSV文件&#xff0c;文件内容包括股票名称、价格和交易量。完成以下任务&#xff1a; 找出价格最高的股票&#xff1b; 计算总交易量&#xff1b; 绘制价格折线图。 代码实现&#xff1a; import pandas as pd import matplotlib.pyplot …

鸿蒙NEXT元服务:论如何免费快速上架作品

【引言】天下武功&#xff0c;唯快不破。 本文讨论如何免费且以最快速度上架自己的作品。 作者以自己从零开始到提交发布审核一共俩小时的操作流程分享给大家作参考。 【1】立项选择 结论&#xff1a;元服务&#xff0c;单机&#xff0c;工具类&#xff08;非游戏&#xff…

el-select 修改样式

这样漂亮的页面&#xff0c;搭配的却是一个白色风格的下拉框 &#xff0c;这也过于刺眼。。。 调整后样式为&#xff1a; 灯红酒绿总有人看着眼杂&#xff0c;但将风格统一终究是上上选择。下面来处理这个问题。 分为两部分。 第一部分&#xff1a;是修改触发框的样式 第二部…

M|两小无猜

title: 两小无猜 Jeux d’enfants time: 2024-12-01 周日 rating: 7 豆瓣: 7.9 上映时间: “2003” 类型: M爱情 导演: 杨塞谬尔 Yann Samuell 主演: 吉约姆卡内 Guillaume Canet玛丽昂歌迪亚 Marion Cotillard 国家/地区: 法国比利时 片长/分钟: 93分钟 M&#xff…

深度学习中的前向传播与损失函数

目录 ​编辑 前向传播&#xff1a;神经网络的推理过程 什么是前向传播&#xff1f; 前向传播的步骤 数学表达 代码示例&#xff1a;前向传播 损失函数&#xff1a;衡量预测与真实值的差异 损失函数的定义 损失函数的作用 常见的损失函数 代码示例&#xff1a;损失函…

桶排序(代码+注释)

#include <stdio.h> #include <stdlib.h>// 定义桶的结构 typedef struct Bucket {int* data; // 动态数组int count; // 当前存储的元素个数int capacity; // 桶的容量 } Bucket;// 初始化桶 void InitBucket(Bucket* bucket) {bucket->capacity 10; // 初…

【Linux】进程控制,手搓简洁版shell

⭐️个人主页&#xff1a;小羊 ⭐️所属专栏&#xff1a;Linux 很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~ 目录 1、进程创建2、进程终止3、进程等待4、进程程序替换5、手写简洁版shell 1、进程创建 fork函数&#xff1a;从已经存在的进程中创…

EasyDarwin搭建直播推流服务

学习链接 easydarwin官网 - 这里看介绍 easydarwin软件下载地址 - 百度网盘 easydarwin视频 B站 文章目录 学习链接使用下载EasyDarwin压缩包&#xff0c;并解压到目录启动EasyDarwin点播直播easyplayer.jsapidocffmpeg推流rtsp & ffplay拉流 使用 下载EasyDarwin压缩包…

云备份实战项目

文章目录 前言一、整体项目简介二、服务端环境及功能简介三、 客户端环境及功能简介四、服务端文件管理类的实现1. 获取文件大小&#xff0c;最后一次修改时间&#xff0c;最后一次访问时间&#xff0c;文件名称&#xff0c;以及文件内容的读写等功能2. 判断文件是否存在&#…

关于ConstarintLayout有关的点

目录 一、概述 二、过程。 1、介绍 主要特点 关键概念 使用示例 总结 2、我遇到的问题 问题&#xff1a; 可能的原因&#xff1a; 结论 一、概述 在学习过程中&#xff0c;发现对ConstarintLayout理解不够到位&#xff0c;下面是发现并解决问题过程。 二、过程。 1…

《数字图像处理基础》学习07-图像几何变换之最近邻插值法放大图像

目录 一&#xff0c;概念 二&#xff0c;题目及matlab实现 1&#xff0c;解题思路 2&#xff0c;matlab实现 1&#xff09;matlab思路 2&#xff09;完整代码 三&#xff0c;放大图像及matlab实现 一&#xff0c;概念 通过上一篇&#xff0c;我已经学习了使用最邻近插…

计网-子网划分

基于本视频观看做的笔记&#xff0c;帮助自己理解 子网掩码&#xff1a;用于识别IP地址中的网络号和主机号的位数 表示方法 第一种.32位二进制数字&#xff0c;在子网掩码中&#xff0c;网络号用”1“表示&#xff0c;主机号用”0“表示 e.g.:IP地址1.1.1.1的子网掩码是255…

【Solidity】入门指南:智能合约开发基础

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 Solidity入门指南&#xff1a;智能合约开发基础引言1. 开发环境搭建1.1 Remix I…

如何高效地架构一个Java项目

引言 Java是企业级应用开发的主流语言之一&#xff0c;而我们作为使用Java语言的程序员&#xff0c;职称有初级、中级、高级、资深、经理、架构&#xff0c;但我们往往只是慢慢通过经验的积累迭代了自己的等级&#xff0c;如果没有保持学习的习惯&#xff0c;大多数程序员会停留…

HTTP 探秘之旅:从入门到未来

文章目录 导言&#xff1a;目录&#xff1a;第一篇&#xff1a;HTTP&#xff0c;互联网的“快递员”第二篇&#xff1a;从点开网页到看到内容&#xff0c;HTTP 究竟做了什么&#xff1f;第三篇&#xff1a;HTTP 的烦恼与进化史第四篇&#xff1a;HTTP 的铠甲——HTTPS 的故事第…

c++:thread(线程)

1.基本使用 1.1创建线程 join()函数用于&#xff1a;主程序等待子线程执行完毕之后再继续 #include <iostream> #include <thread>void printHello() {std::cout << "hello world" << std::endl; }int main() {// 1.创建线程std::thread …

第六届金盾信安杯-SSRF

操作内容&#xff1a; 进入环境 可以查询网站信息 查询环境url https://114.55.67.167:52263/flag.php 返回 flag 就在这 https://114.55.67.167:52263/flag.php 把这个转换成短连接&#xff0c;然后再提交 得出 flag

SpringMVC(2)

前言 这一节我们终结springmvc 1. SSM整合配置 先导入坐标 先创建包 配置类 然后开始创建jdbc的config和mybatis的config&#xff0c;还有properties SpringConfig&#xff1a; jdbc.properties&#xff1a; JdbcConfig: MybatisConfig: 下面开始spring整合mvc&#…

零基础Python学习

1.环境搭建 1.1 安装运行环境python3.13 Welcome to Python.org 1.2 安装集成开发环境PyCharm PyCharm: the Python IDE for data science and web development 1.3 创建项目 && 设置字体 2.基础语法 2.1 常量与表达式 在python中整数除整数不会优化&#xff0c;所…

vue3项目创建方式记录

目录 创建vue3常用的方式有三种&#xff1a;一.使用vue cli创建二.使用vite创建三.使用vue3官方推荐创建方式&#xff08;create-vue&#xff09; 创建vue3常用的方式有三种&#xff1a; 一.使用vue cli创建 vue create 项目名二.使用vite创建 vite是下一代前端开发与构建工…