java面试之ThreadLocal问题

什么是ThreadLocal,它的基本用法是什么 

简单来说就是能在多线程中保持变量独立的线程对象

不用Threadlocal多线程访问同一个变量会出现的问题

package com.pxx;/*** Created by Administrator on 2023/9/3.*/
public class Demo1 {private String v1;public String getV1() {return v1;}public void setV1(String v1) {this.v1 = v1;}public static void main(String[] args) {//开启一个多线程去设置并且访问这个变量Demo1 d1 = new Demo1();//这里会循环五个线程for(int i = 0;i < 5;i++) {Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {//设置并且打印一个变量的数据d1.setV1("data:" + Thread.currentThread().getName());System.out.println("-------------");//取出这个线程对应的名字和值System.out.println(Thread.currentThread().getName() + "=>" + d1.getV1());}});//设置一下每一个线程的名字t1.setName("线程" + i);t1.start();//开启直接进入到运行状态,然后当前线程开始运行,然后进行下一次循环,下一个线程进来,这个时候进程可能会仙湖干扰}}
}

下面直接已经线程混乱 

 一般来说我们可以用锁来解决,比如引入synchronized,这里我们先不用锁,我们用ThreadLocal这个类去解决

ThreadLocal类去解决线程不同步的问题

它的目的是保持变量独立

下面我们去看一下常见的方法

set():将变量绑定到当前线程中

get():获取当前线程绑定的变量

修改一下上面的代码

package com.pxx;/*** Created by Administrator on 2023/9/3.*/
public class Demo1 {//引入绑定变量的线程对象ThreadLocal<String>  tl1= new ThreadLocal();private String v1;public String getV1() {// return v1;return tl1.get();//得到通过set绑定的变量}public void setV1(String v1) {//this.v1 = v1;tl1.set(v1);//直接把这个v1绑定到对象里面}public static void main(String[] args) {Demo1 d1 = new Demo1();//这里会循环五个线程for(int i = 0;i < 5;i++) {Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {//设置并且打印一个变量的数据d1.setV1("data:" + Thread.currentThread().getName());System.out.println("-------------");//取出这个线程对应的名字和值System.out.println(Thread.currentThread().getName() + "=>" + d1.getV1());}});//设置一下每一个线程的名字t1.setName("线程" + i);t1.start();//开启直接进入到运行状态,然后当前线程开始运行,然后进行下一次循环,下一个线程进来,这个时候进程可能会仙湖干扰}}
}

运行结果:

 ThreadLocal与synchronized的区别

先把上面的代码变成synchronized给锁住

package com.pxx;/*** Created by Administrator on 2023/9/3.*/
public class Demo3 {//引入绑定变量的线程对象ThreadLocal<String>  tl1 = new ThreadLocal();private String v1;public String getV1() {return v1;}public void setV1(String v1) {this.v1 = v1;}public static void main(String[] args) {Demo3 d1 = new Demo3();//这里会循环五个线程for(int i = 0;i < 5;i++) {Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {synchronized (d1) {//这个加锁了//设置并且打印一个变量的数据d1.setV1("data:" + Thread.currentThread().getName());System.out.println("-------------");//取出这个线程对应的名字和值System.out.println(Thread.currentThread().getName() + "=>" + d1.getV1());}}});//设置一下每一个线程的名字t1.setName("线程" + i);t1.start();//开启直接进入到运行状态,然后当前线程开始运行,然后进行下一次循环,下一个线程进来,这个时候进程可能会仙湖干扰}}}

运行结果:

很明显是锁住了

先来说一下两者的共同点:都是处理多线程并发访问变量的问题

synchronized:它的效率会低一点,因为相当于就是说,线程是排队进行访问的,就像一个教室只有一个厕所,大家都要进去上,就要排队

ThreadLocal:效率高,相当于线程可以同时并发访问,效率高,就像一个教室多个厕所,彼此上,但是相互独立

ThreadLocal的内部结构

最早的一个设计原理

 JDK8的设计原理

关注一下JDK8,它是把Thread每一个线程作为了一个主线,然后Entry里面存放的是 ThreadLocal这样一个线程对象

这样的设计方案有两个好处:

1.每个map存储的entry变少,因为就是怎么说,Thread线程肯定比ThreadLocal这样一个线程多

2.那么主线Thread销毁掉,里面的map数据对象也就被销毁了

我分析一下源码

先去看set方法

再去看一下ThreadLocalMap这个类 

 

set就是添加到了这个map对象里面

这样不就说明一个问题:解决了线程并发访问,变量出错的问题

相当是什么,自己去上自己的厕所,彼此之间相互独立不影响

 可能会造成的一个内存泄漏的问题

他分为两种情况来看:

第一种: 内存不够了,只有溢出memory overflow

第二种:内存泄漏memory leak,在堆上的空间得不到释放,会造成浪费,影响了程序的运行速度,这种浪费多了,就会造成内存的溢出 

我们这里再来引入两个概念

第一个:什么是强引用?我们正常的引用一个对象,没有指向的时候,就会被gc掉,也就是垃圾回收器给回收掉

第二个:什么是弱引用?一句来说,遇到gc就会被回收。只要垃圾回收机制一运行,不管jvm的内存空间时候是否足够,都会回收该对象占用的内存

下面用一张图展示一下引用关系

假如是key是强引用的情况

假设ThreadLocal用完了,引用被收回,又因为Map里面的ThreadLocal是一个强引用,所以ThreadLocal对象无法被回收掉

在没手动remove掉Entry类以及CurrentThread依然运行的情况下,Entry类根本不会被挥挥手,会造成内存泄漏

假设key是弱引用的情况下,ThreadLocal引用没了,map 里面是一个弱引用指向ThreadLocal,那么就表明ThreadLocal会马上被垃圾回收器给回收掉,他一回收掉,Key就为NULL,那么我们就再也无法访问到value ,value无法被回收,会导致内存泄漏

很明显源代码给出的是一个弱引用

上面也说明了强引用还是弱引用都会造成内存泄漏

那么造成内存泄漏的根本原因就是:

第一点:Entry类始终存在内存中,没有手动remove

第二点:CurrentThread线程依然在运行

好了,祝你早安午安晚安。

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

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

相关文章

非科班菜鸡算法学习记录 | 代码随想录算法训练营第57天|| 647. 回文子串 516.最长回文子序列 动态规划总结篇

647. 回文子串 知识点&#xff1a;动规 状态&#xff1a;看思路自己写 思路&#xff1a; dp不好想&#xff0c;dp[i][j] 是指左闭右闭时&#xff0c;是否为回文,bool类型&#xff1b; 注意递归公式和遍历顺序 class Solution { public:int countSubstrings(string s) {int …

音频——I2S TDM 模式(六)

I2S 基本概念飞利浦(I2S)标准模式左(MSB)对齐标准模式右(LSB)对齐标准模式DSP 模式TDM 模式 文章目录 TDM formatTDM format ATDM format BTDM format C总结 TDM format TDM 一般有三种常用操作模式&#xff1a;TDM A mode &#xff0c;TDM B mode 和 TDM C mode&#xff0c; …

【算法系列篇】模拟算法

文章目录 前言1.替换所有问号1.1 题目要求1.2 做题思路1.3 Java代码实现 2. 提莫攻击2.1 题目要求2.2 做题思路2.3 Java代码实现 3. N 字形变换3.1 题目要求3.2 做题思路3.3 Java代码实现 4. 外观数列4.1 题目要求4.2 做题思路4.3 Java代码实现 5. 数青蛙5.1 题目要求5.2 做题思…

安防监控/视频存储/视频汇聚平台EasyCVR如何接入智能分析网关V4?

TSINGSEE青犀AI边缘计算网关硬件 —— 智能分析网关目前有5个版本&#xff1a;V1、V2、V3、V4、V5&#xff0c;每个版本都能实现对监控视频的智能识别和分析&#xff0c;支持抓拍、记录、告警等&#xff0c;每个版本在算法模型及性能配置上略有不同。硬件可实现的AI检测包括&am…

VMware虚拟机安装CentOS7设置静态ip

vim /etc/sysconfig/network-scripts/ifcfg-ens33修改BOOTPROTO的值为static 增加最后那四项&#xff0c;参数在编辑&#xff0c;虚拟网络编辑器里面看

如何远程访问Linux MeterSphere一站式开源持续测试平台

文章目录 前言1. 安装MeterSphere2. 本地访问MeterSphere3. 安装 cpolar内网穿透软件4. 配置MeterSphere公网访问地址5. 公网远程访问MeterSphere6. 固定MeterSphere公网地址 前言 MeterSphere 是一站式开源持续测试平台, 涵盖测试跟踪、接口测试、UI 测试和性能测试等功能&am…

【算法专题突破】双指针 - 和为s的两个数字(6)

目录 1. 题目解析 2. 算法原理 3. 代码编写 写在最后&#xff1a; 1. 题目解析 题目链接&#xff1a;剑指 Offer 57. 和为s的两个数字 - 力扣&#xff08;Leetcode&#xff09; 这道题题目就一句话但是也是有信息可以提取的&#xff0c; 最重要的就是开始的那句话&#…

【LeetCode】19. 删除链表的倒数第 N 个结点

19. 删除链表的倒数第 N 个结点&#xff08;中等&#xff09; 方法&#xff1a;快慢指针 思路 为了找到倒数第 n 个节点&#xff0c;我们应该先找到最后一个节点&#xff0c;然后从它开始往前数 n-1 个节点就是要删除的节点。 对于一般情况&#xff1a;设置 fast 和 slow 两个…

Golang编写客户端SDK,并开源发布包到GitHub,供其他项目import使用

目录 编写客户端SDK&#xff0c;并开源发布包到GitHub1. 创建 GitHub 仓库2. 构建项目&#xff0c;编写代码Go 代码示例&#xff1a;项目目录结构展示&#xff1a; 3. 提交代码到 GitHub仓库4. 发布版本5. 现在其他人可以引用使用你的模块包了 编写客户端SDK&#xff0c;并开源…

个人博客项目测试报告

目录 一. 项目背景 二. 概述 三. 功能测试用例 四. 自动化测试用例 一. 项目背景 项目链接: http://81.70.189.104:8080/login.html 个人博客系统提供了 登录、注册、写博客&发布博客、删除博客、修改博客功能。前端的页面有 登录页、注册页、个人博客列表页、博客详情…

CloudCompare 二次开发(9)——半径滤波

目录 一、概述二、代码集成三、结果展示本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫。 一、概述 使用CloudCompare与PCL的混合编程实现点云半径滤波。半径滤波的算法原理见:PCL 半径滤波器。基于PCL将半径滤波集成到Cl…

c#事件(event)

概述&#xff1a; C#中的事件是一种特殊的委托&#xff0c;它用于实现观察者模式&#xff0c;允许对象在特定事件发生时通知其他对象。 以下是使用C#事件的示例&#xff1a; 首先&#xff0c;定义一个包含事件的类&#xff1a; public class EventPublisher {// 声明一个事…

通俗易懂讲解大模型:Tokenizer

Tokenizer Tokenizer 是 NLP pipeline 的核心组件之一。Tokenizer 的目标是&#xff1a;将文本转换为模型可以处理的数据。模型只能处理数字&#xff0c;因此 Tokenizer 需要将文本输入转换为数字输入。 通常而言有三种类型的 Tokenizer &#xff1a;Word-based Tokenizer、Cha…

PostgreSQL安装异常,服务无法启动导致创建服务器超时

win上安装pg后无法创建服务器&#xff0c;提示创建超时&#xff0c;发现服务列表里面pg15服务 并没有启动&#xff0c;启动服务器发现服务不了&#xff0c;截图忘记截了&#xff0c;复现不了&#xff0c;解决方法是 换个身份&#xff0c;然后继续启动&#xff0c;然后就可以在…

【每日运维】U盘启动盘安装 ESXi 6.7.0 安装卡在 loading /bnxtroce.v00

问题描述 ● ESXi 6.7.0 安装进度卡在loading /bnxtroce.v00 进度处 处理方法 ● 重新制作启动盘&#xff0c;写入方式改为&#xff1a;【USB-ZIPv2】 ● 设置服务器的 bios设置&#xff0c;启动方式改为【UEFI】 ● 重启开机安装即可

Playwright for Python:断言

一、支持的断言 Playwright支持以下几种断言&#xff1a; 断言描述expect(locator).to_be_checked()复选框被选中expect(locator).to_be_disabled()元素是禁用状态expect(locator).to_be_editable()元素是可编辑状态expect(locator).to_be_empty()容器是空的expect(locator).…

QT 发布软件基本操作

一、配置环境变量 找到Qt安装时的bin目录的路径&#xff1a;D:\Qt\Qt5.14.2\5.14.2\mingw73_64\bin&#xff0c;将目录拷贝至下述环境变量中。 打开计算机的高级系统设置 选中环境变量-->系统变量-->Path 点击编辑-->新建-->粘贴 二、生成发布软件的可执行程序 …

圆点和元素连线

效果图&#xff1a; 点上的线段跟踪元素移动&#xff0c;并且线会根据鼠标位置来连接元素的那个角 实现代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><style>* {padding: 0;margin: 0;}.piont {width…

DP读书:鲲鹏处理器 架构与编程(十四)ACPI与软件架构具体调优

一分钟速通ACPI和鲲鹏软件移植 操作系统内核鲲鹏软件移植鲲鹏软件移植流程 编译工具选择编译参数移植案例源码修改案例鲲鹏分析扫描工具 Dependency Advisor鲲鹏代码迁移工具 Porting Advisor 鲲鹏软件性能调优鲲鹏软件性能调优流程CPU与内存子系统性能调优网络子系统性能调优磁…

库中是如何实现string类的?

&#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;推荐专栏1: &#x1f354;&#x1f35f;&#x1f32f;C语言初阶 &#x1f43b;推荐专栏2: &#x1f354;&#x1f35f;&#x1f32f;C语言进阶 &#x1f511;个人信条: &#x1f335;知行合一 &#x1f…