JUC P8 ThreadLocal 基础+代码

JUC P8 ThreadLocal 基础+代码

教程:https://www.bilibili.com/video/BV1ar4y1x727?p=100

引出问题

ThreadLocal 和 TreadLocalMap 数据结构关系?
ThreadLocal 中的 key 是弱引用,为什么?
ThreadLocal 内存泄漏问题是什么?
ThreadLocal 中最后为什么要加 remove 方法?

1. ThreadLocal 描述

ThreadLocal 提供线程局部变量。这些变量与正常的变量不同,因为每个线程在访问 ThreadLocal 实例的时候(通过 get 或 set 方法)都有自己的、独立初始化的变量副本。ThreadLocal 实例通常是类中的私有静态字段,使用它的目的是希望将状态(例如,用户 ID 或事务 ID)与线程关联起来。

2. 应用

2.1 五个销售卖房子,集团高层只关心销售总量的准确统计数

实例方法上锁

@Slf4j(topic = "c.Test")
public class Test {public static void main(String[] args) {House house = new House();for (int i = 0; i < 5; i++) {new Thread(() -> {int size = new Random().nextInt(10) + 1;log.info("{} 卖出了 {} 套房子", Thread.currentThread().getName(), size);for (int j = 0; j < size; j++) {house.saleHouse();}}, "t" + i).start();}try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {throw new RuntimeException(e);}log.info("{} 共卖出了 {} 套房子", Thread.currentThread().getName(), house.saleCount);}
}class House {public int saleCount;public synchronized void saleHouse() {saleCount++;}
}

在这里插入图片描述

2.2 五个销售都有自己的销售额指标,自己专属自己的,不和别人掺和

@Slf4j(topic = "c.Test")
public class Test {public static void main(String[] args) {House house = new House();for (int i = 0; i < 5; i++) {new Thread(() -> {int size = new Random().nextInt(10) + 1;for (int j = 0; j < size; j++) {house.saleVolumeByThreadLocal();}log.info("{} 卖出了 {} 套房子", Thread.currentThread().getName(), house.saleVolume.get());}, "t" + i).start();}}
}class House {ThreadLocal<Integer> saleVolume = ThreadLocal.withInitial(() -> 0);public void saleVolumeByThreadLocal() {saleVolume.set(saleVolume.get() + 1);}
}

在这里插入图片描述

这样写的隐患:
线程池的场景下因为线程会复用,如果不清理自定义的 ThreadLocal 变量,可能会影响后续业务逻辑和造成内存泄漏等问题。尽量在代理中使用 try-finally 块进行回收。

try {int size = new Random().nextInt(10) + 1;for (int j = 0; j < size; j++) {house.saleVolumeByThreadLocal();}log.info("{} 卖出了 {} 套房子", Thread.currentThread().getName(), house.saleVolume.get());
} finally {house.saleVolume.remove();
}

2.3 线程池场景

不清理 ThreadLocal 变量

@Slf4j(topic = "c.Test")
public class Test {public static void main(String[] args) {MyData myData = new MyData();ExecutorService threadPool = Executors.newFixedThreadPool(3);try {for (int i = 0; i < 10; i++) {threadPool.submit(() -> {Integer before = myData.threadLocalField.get();myData.add();Integer after = myData.threadLocalField.get();log.info("before: {} -> after: {}", before, after);});}} finally {threadPool.shutdown();}}
}class MyData {public ThreadLocal<Integer> threadLocalField = ThreadLocal.withInitial(() -> 0);public void add() {threadLocalField.set(threadLocalField.get() + 1);}
}

在这里插入图片描述
每个线程每执行完自己的任务后就应该恢复到原始状态,否则会影响到后续的线程。

清理 ThreadLocal 变量

@Slf4j(topic = "c.Test")
public class Test {public static void main(String[] args) {MyData myData = new MyData();ExecutorService threadPool = Executors.newFixedThreadPool(3);try {for (int i = 0; i < 10; i++) {threadPool.submit(() -> {try {Integer before = myData.threadLocalField.get();myData.add();Integer after = myData.threadLocalField.get();log.info("before: {} -> after: {}", before, after);} finally {// 清除线程变量myData.threadLocalField.remove();}});}} finally {threadPool.shutdown();}}
}class MyData {public ThreadLocal<Integer> threadLocalField = ThreadLocal.withInitial(() -> 0);public void add() {threadLocalField.set(threadLocalField.get() + 1);}
}

在这里插入图片描述

3. 面试题

3.1 Thread,ThreadLocal,ThreadLocalMap 关系

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

ThreadLocalMap 从字面上可以看出这是一个保存 ThreadLocal 对象的 map,以 ThreadLocal 为 key。

JVM 内部维护了一个线程版的 Map<ThreadLocal, Value>,(通过 ThreadLocal 对象的 set 方法,结果把 ThreadLocal 对象自己当作 key,放进了 ThreadLocalMap 中),每个线程要用到这个线程的时候,用当前的线程去 Map 中获取,通过这样让每个线程都有了自己独立的变量,人手一份,竞争条件被彻底消除,在并发模式下是绝对安全的变量。

3.2 ThreadLocal 内存泄漏问题

内存泄漏:占着茅坑不拉屎,不再使用的对象占用的内存不能被回收。

为什么要用弱引用?

To help deal with very large and long-lived usages, the hash table entries use WeakReferences for keys. However, since reference queues are not used, stale entries are guaranteed to be removed only when the table starts running out of space.

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4. 最佳实践

  1. 初始化方式:
ThreadLocal<Integer> threadLocalField = ThreadLocal.withInitial(() -> 0);
  1. 建议把 ThreadLocal 修饰为 static
    在这里插入图片描述
    在这里插入图片描述

  2. 线程使用 ThreadLocal 完之后必须进行 remove 回收

  3. 使用条件
    在这里插入图片描述

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

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

相关文章

协程 VS 线程,Kotlin技术精讲

协程(coroutines)是一种并发设计模式&#xff0c;您可以在Android 平台上使用它来简化异步执行的代码。协程是在版本 1.3 中添加到 Kotlin 的&#xff0c;它基于来自其他语言的既定概念。 在 Android 上&#xff0c;协程有助于管理长时间运行的任务&#xff0c;如果管理不当&a…

创邻科技图数据库课程走进一流高校

《图数据库原理和实践》 正式开课&#xff01; 最近&#xff0c;浙江大学计算机学院新开了一门名为 《图数据库原理和实践》 的新课程&#xff0c;该课程由创邻科技和浙江大学联合推出&#xff0c;吸引了许多学生踊跃参与&#xff01; 曾为浙大学子的创邻科技CTO周研博士作为…

51单片机-直流电机学习

简介 51单片机采用的是5V的直流电机 轴长&#xff1a;8mm 轴径&#xff1a;2mm 电压&#xff1a;1-6V 参考电流&#xff1a;0.35-0.4A 3V 转速&#xff1a;17000-18000 转每分钟 他的组成&#xff1a; 直流电机的结构应由 定子 和 转子 两大部分组成。 直流电机运行时静止…

如何在 Ubuntu 上安装 Nagios?

Nagios 的功能 Nagios 的一些关键功能包括&#xff1a; 主机和服务监控&#xff1a; Nagios 允许您使用提供实时状态数据的插件来监控主机&#xff08;可以是物理机或虚拟机&#xff09;以及 HTTP、SSH 和 SMTP 等服务。此功能使您能够全面了解整个基础设施的运行状况和可用性…

Java(一)安装并使用 java(Windows)

安装并使用java 前言一、初识Java1.Java的安装1.1下载JDK1.2JDK安装与使用1.2.1安装1.2.2 IDEA&#xff08;编译器&#xff09;使用 2.Java运行编程逻辑&#xff08;重要后面要用&#xff09;总结 前言 学习很重要&#xff0c;复习也很重要&#xff0c;对于编程语言的复习更为…

开源|HDR-ISP开源项目介绍

引言 拖更很久了&#xff0c;本着出品必精的原则&#xff0c;我们更新就来点干货。想起刚入行时&#xff0c;网上并没有很多以及系统的ISP的学习资料&#xff0c;都是边工作、边搜集资料然后边学习&#xff0c;一路坎坎坷坷走到今天算是刚入了ISP的大门。 为了解决新人入门的…

JetBrains出品的IDE自动补全和提示文档设置

如题下图设置前景色和背景色&#xff1a; 效果如下图&#xff0c;标识1是Completion&#xff0c;标识2是Documentation&#xff1a;

1.8 工程相关解析(各种文件,资源访问

目录 1.8 工程相关解析(各种文件&#xff0c;资源访问) 分类 Android 基础入门教程 本节引言&#xff1a; 1.工程项目结构解析&#xff1a; 1.res资源文件夹介绍&#xff1a; 2.如何去使用这些资源 2.深入了解三个文件&#xff1a; MainActivity.java&#xff1a; 布局…

将 Qt Designer 的 ui 文件转换为 PySide2 使用的.py 文件

20201206 修订&#xff1a;在 Pyside2 的 5.15.2 版本中&#xff0c;从 ui 生成 py 文件过程&#xff0c;命令从 “uic” 变为 “pyside2-uic” Qt Designer 设计的 ui 文件&#xff0c;就是一个 xml 文件&#xff0c;通过 pyside-uic 可以转换成标准的.py 文件 。通过 QtDesi…

电商(淘宝1688京东拼多多等)API接口服务:提升商业效率和用户体验的关键

电商API接口服务&#xff1a;提升商业效率和用户体验的关键 随着电子商务的飞速发展&#xff0c;电商企业需要不断提升自身的业务能力和服务质量&#xff0c;以应对日益激烈的市场竞争。为了更好地满足商家和消费者的需求&#xff0c;电商API接口服务应运而生。本文将探讨电商…

Flink--2、Flink部署(Yarn集群搭建下的会话模式部署、单作业模式部署、应用模式部署)

星光下的赶路人star的个人主页 你必须赢过&#xff0c;才可以说不在乎输赢 文章目录 1、Flink部署1.1 集群角色1.2 Flink集群搭建1.2.1 集群启动1.2.2 向集群提交作业 1.3 部署模式1.3.1 会话模式&#xff08;Session Mode&#xff09;1.3.2 单作业模式&#xff08;Per-Job Mod…

华为云云耀云服务器L实例评测|使用Linux系统与Docker部署.net/c#项目

目录 前言 如何在CentOS运行项目 登录CentOS 使用Rider打包 使用Visual Studio打包 项目运行 后台运行 开放端口 如何在Docker中运行项目 项目运行 前言 本章详细介绍&#xff0c;.net Core项目从打包到部署上华为云云耀云服务器L实例的过程与一些细节问题。在这里…

Outlook无需API开发连接钉钉群机器人,实现新增会议日程自动发送群消息通知

Outlook用户使用场景&#xff1a; 在企业中&#xff0c;会议和活动的顺利举行对于业务运转和团队协作至关重要。然而&#xff0c;计划的变动总是无法避免&#xff0c;这可能会导致其他人的计划受到影响&#xff0c;打乱原有的安排。为了解决这个问题&#xff0c;许多企业开始使…

快速构建基于Paddle Serving部署的Paddle Detection目标检测Docker镜像

快速构建基于Paddle Serving部署的Paddle Detection目标检测Docker镜像 项目介绍需要重点关注的几个文件构建cpu版本的docker构建gpu版本的docker&#xff08;cuda11.2cudnn8&#xff09; 阅读提示&#xff1a; &#xff08;1&#xff09;Paddle的Serving项目中&#xff0c;在t…

【autodl/linux配环境心得:conda/本地配cuda,cudnn及pytorch心得】-未完成

linux配环境心得&#xff1a;conda/本地配cuda&#xff0c;cudnn及pytorch心得 我们服务器遇到的大多数找不到包的问题一&#xff0c;服务器安装cuda和cudnn使用conda在线安装cuda和cudnn使用conda进行本地安装检查conda安装的cuda和cudnn本地直接安装cuda和cudnn方法一&#x…

Linux Debian12将本地项目上传到码云(gitee)远程仓库

一、注册码云gitee账号 这个可以参考其他教程&#xff0c;本文不做介绍。 gitee官网&#xff1a;https://gitee.com/ 二、Linux Debian12安装git 如果Linux系统没有安装git&#xff0c;可以使用下面命令安装git sudo apt install git 三、gitee新建仓库 我这只做测试&…

69、配置AWS服务,接收来自RTSP流的推送

基本思想:在上一篇的基础和视频教程之后,进行简单的aws服务,进行RTSP流的接收 第一步: 第二步:配置video_stream,记得选择香港节点 同时记录这个信息,后面的策略需要填充 第三步:进行策略设置 第四步:策略设置,选中右上角的创建策略 第五步、进行json填充 第六步:填…

精益创业的三个测量方法

精益创业三个测量工具【安志强趣讲282期】 趣讲大白话&#xff1a;没法度量就没法改进 **************************** 工具1&#xff1a;AB对比测试 就是产品有两个或多个版本 然后通过外部客户或内部人员评测 可以组织天使用户群&#xff1a;愿意参与的专业人士 工具2&#x…

微服务井喷时代,我们如何规模化运维?

随着云原生技术发展及相关技术被越来越多运用到公司生产实践当中&#xff0c;有两种不可逆转的趋势&#xff1a; 1、微服务数量越来越多。原来巨型单体服务不断被拆解成一个个微服务&#xff0c;在方便功能复用及高效迭代的同时&#xff0c;也给运维带来了不少挑战&#xff1a;…

大数据技术之Hadoop:MapReduce与Yarn概述(六)

目录 一、分布式计算 二、分布式资源调度 2.1 什么是分布式资源调度 2.2 yarn的架构 2.2.1 核心架构 2.2.2 辅助架构 前面我们提到了Hadoop的三大核心功能&#xff1a;分布式存储、分布式计算和资源调度&#xff0c;分别由Hadoop的三大核心组件可以担任。 即HDFS是分布式…