深入理解Java ThreadLocal及其内存泄漏防范
文章目录
- 一、ThreadLocal简介
- 二、ThreadLocal的内存泄漏问题
- 三、防止ThreadLocal导致的内存泄漏
- 四、总结
一、ThreadLocal简介
在Java中,ThreadLocal是一种线程封闭的机制,其主要目的是为每个线程都创建一个单独的变量副本。这意味着,每个线程都可以独立地改变自己的副本,而不会影响其他线程的副本。
ThreadLocal常被用于解决多线程编程中的数据同步问题。例如,我们可以用ThreadLocal来保存数据库连接、Session等常见的线程不安全的变量。
然而,ThreadLocal并非完全没有问题。如果使用不当,ThreadLocal可能会导致内存泄漏,这也是我们今天主要关注的问题。
ThreadLocal<String> threadLocal = new ThreadLocal<>();
threadLocal.set("Hello, world");
String value = threadLocal.get();
System.out.println(value);
// 输出:Hello, world
二、ThreadLocal的内存泄漏问题
在探讨ThreadLocal的内存泄漏问题前,我们需要明白其原因。在ThreadLocal中,每个线程保存的变量值存储在ThreadLocalMap中,这是Thread类的一个属性。每个ThreadLocal实例作为Key,而变量副本则作为Value。
然而,这个Key是对ThreadLocal实例的弱引用。这意味着,如果没有其他地方强引用这个ThreadLocal实例,那么在下一次垃圾回收时,这个ThreadLocal实例就会被回收。然而,由于ThreadLocalMap对Value的引用是强引用,所以即使ThreadLocal实例被回收,Value对象依然不会被回收,如果线程一直不结束,这个Value对象就会一直存在于ThreadLocalMap中,从而导致内存泄漏。
三、防止ThreadLocal导致的内存泄漏
知道了内存泄漏的原因,我们就可以进行针对性的防范了。主要有以下两种方式:
-
手动清理ThreadLocal存储的数据
ThreadLocal提供了一个remove()方法,可以删除当前线程的局部变量。在使用完ThreadLocal后,我们应该主动调用这个方法,清除ThreadLocalMap中的数据。这样做的好处是,即使ThreadLocal实例被回收,ThreadLocalMap中也不会留下无用的数据,从而防止内存泄漏。
ThreadLocal<String> threadLocal = new ThreadLocal<>(); threadLocal.set("Hello, world"); //... // 使用完ThreadLocal后,清除数据 threadLocal.remove(); -
正确使用线程池
对于使用线程池的场景,需要特别注意。因为线程池中的线程执行完任务后,不会立即结束,而是可能被再次
利用。这就导致线程的ThreadLocalMap会一直存在,从而可能导致内存泄漏。
对于这种情况,我们需要在每个任务执行结束后,都清理掉ThreadLocal存储的数据。
ThreadLocal<String> threadLocal = new ThreadLocal<>();ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {executorService.execute(() -> {threadLocal.set("Hello, world");//...// 任务执行结束后,清除ThreadLocal数据threadLocal.remove();});
}// 使用完线程池后,关闭线程池
executorService.shutdown();
四、总结
ThreadLocal是Java中一个强大的工具,它为每个线程提供了独立的变量副本,从而在多线程环境中实现了数据的隔离。然而,使用不当,ThreadLocal也可能会导致内存泄漏,造成应用程序性能下降,甚至出现错误。因此,我们在使用ThreadLocal的过程中,应该养成良好的编程习惯,正确清理ThreadLocalMap中的数据,防止内存泄漏的发生。
相关文章:
深入理解Java ThreadLocal及其内存泄漏防范
文章目录 一、ThreadLocal简介二、ThreadLocal的内存泄漏问题三、防止ThreadLocal导致的内存泄漏四、总结 一、ThreadLocal简介 在Java中,ThreadLocal是一种线程封闭的机制,其主要目的是为每个线程都创建一个单独的变量副本。这意味着,每个线…...
介绍10款ChatGPT替代产品
ChatGPT 引领着聊天 AI 的世界,许多人已经开始在日常生活中使用它。OpenAI 的 GPT-3 语言模型是聊天机器人的基础,它使得用户能够通过回答问题与 AI 进行交互。 GPT-4 的引入为机器人提供了更强大的功能。然而,它也有一个明显的缺点ÿ…...
数字逻辑 期末
概述 教材:《电子技术基础(数字部分)》 第六版 7400系列是TTL型芯片,商用型 数制 十进制->二进制 除2取余法&乘2取整法(注意精度,但计科简单不考) 十六进制->二进制 一位变四位 八…...
MT4交易外汇平台有哪些优势?为何是外汇投资首选?
外汇市场上存在着各种各样的外汇交易商,但是很多的外汇交易商所选择的交易平台都是MT4交易外汇平台。作为全世界范围内使用最为广泛的交易平台,MT4交易外汇平台具有哪些优势,能够让外汇交易商和外汇投资者都选择使用。本文就来具体的聊聊&…...
问卷调查工具实力榜单发布
问卷调查是从目标受众那里收集有价值的反馈和见解的有效方式。正确的调查问卷工具可以使问卷的创建、分发和分析变得更加容易和高效。在本文中,我们将问卷调查工具排行榜实力榜,为大家选择问卷平台的时候提供有价值的参考意见。 1、Zoho Survey Zoho S…...
javascript中property和attribute有什么区别?
在JavaScript中,“property”(属性)和"attribute"(属性)这两个术语用于描述对象的特性,但它们在含义和用法上有一些区别。 1、属性(Properties): 属性是属于J…...
快速上手kettle
一、前言 最近由于工作需要,需要用到kettle工具进行数据迁移转换。特意找资料学习了一下,kettle基本操作算是学会了。 所学的也结合实际工作进行了验证。为了防止以后用到忘记了,便写了几篇文章记录一下。 二 、ETL简介 ETL ( Extract-Tran…...
Leetcode 399. 除法求值
Leetcode 399. 除法求值题目 给你一个变量对数组 equations 和一个实数值数组 values 作为已知条件,其中 equations[i] [Ai, Bi] 和 values[i] 共同表示等式 Ai / Bi values[i] 。每个Ai 或 Bi 是一个表示单个变量的字符串。另有一些以数组 queries 表示的问题&am…...
kotlin协程并发/并行与串行互相切换,CoroutineScope与await
kotlin协程并发/并行与串行互相切换,CoroutineScope与await import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.launch import java.time.LocalTimefun main(args: Arra…...
初识linux之简单了解TCP协议与UDP协议
目录 一、理解源IP地址和目的IP地址 二、端口号 1. 为什么要有端口号 2. 理解端口号 3. 源端口号和目的端口号 三、初步了解TCP协议和UDP协议 1. 初步认识TCP协议 2. 初步认识UDP协议 3. 可靠传输与不可靠传输 四、网络字节序 1. 网络字节序的概念 2. 如何形成网络…...
【String——简单使用】
文章目录 String1. 字符串定义和初始化2. 字符串基本操作2.1 访问单个字符2.2 修改字符串内容2.3 字符串查找和比较 3. 常用字符串函数3.1 length() 和 size()3.2 empty()3.3 substr()3.4 c_str() 4.字符与整形之间相互转换4.1 char 类型转 int 类型4.2 int 类型转 char 类型4.…...
Python下Taobao封装API接口的优势
Python是一门面向对象编程的语言,封装是面向对象编程中的一种重要概念,它把数据和方法包装在一起,实现了对数据的保护和控制。Python封装接口的优势如下: 1.安全性 封装可以保证数据的安全性,禁止外部对数据的直接访…...
LeetCode 49 字母异位词分组
LeetCode 49 字母异位词分组 来源:力扣(LeetCode) 链接:https://leetcode.cn/problems/group-anagrams/description/ 博主Github:https://github.com/GDUT-Rp/LeetCode 题目: 给你一个字符串数组&#x…...
( 链表) 142. 环形链表 II——【Leetcode每日一题】
❓142. 环形链表 II 难度:中等 给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定…...
论文解读 | 基于改进点对特征的点云6D姿态估计
原创 | 文 BFT机器人 01 摘要 点对特征(PPF)方法已被证明是一种有效的杂波和遮挡下的姿态估计方法。 文章的改进方法主要包括: (1)一种基于奇偶规则求解封闭几何的法向的方法; (2)通过将体素网格划分为等效角度单元的有效降采样方法; (3)基于拟合点的验证步骤。在真实杂波数据集…...
Shell脚本while循环语句应用
记录:433 场景:Shell脚本while循环语句应用。Shell脚本while循环语句应用。while do done、while : do done、while true do done。 版本:CentOS Linux release 7.9.2009。 1.while常用格式 1.1格式一:while do done while c…...
Kubernetes Dashboard + Ingress 及其 yaml 文件分析
概述 记录部署Dashboard Ingress的具体过程及其 yaml 文件分析 Dashboard Yaml # Copyright 2017 The Kubernetes Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the Li…...
【SpringCloud组件——Nacos】
前置准备: 分别提供订单系统(OrderService)和用户系统(UserService)。订单系统主要负责订单相关信息的处理,用户系统主要负责用户相关信息的处理。 一、服务注册与发现 1.1、在父工程当中引入Nacos依赖 …...
pinia状态管理 用法
Pinia是一个用于vue的状态管理库,类似于vuex,是vue的另一种状态管理工具。 Pinia 是 Vue 的存储库,它允许跨组件/页面共享状态。实际上,Pinia就是Vuex的升级版,官网也说过,为了尊重原作者,所以取名pinia&am…...
Oracle客户端版本安装
一、版本准备 Oracle版本下载官网:Instant Client for Linux x86-64 (64-bit) | Oracle 中国 进入网站下载对应的oracle版本,通常环境所用的包有:basic、sdk、sdkplus三个包。包的类型分为rpm和zip包,均可以下载,当前…...
网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...
Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...
Zustand 状态管理库:极简而强大的解决方案
Zustand 是一个轻量级、快速和可扩展的状态管理库,特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...
聊聊 Pulsar:Producer 源码解析
一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…...
STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...
基于Uniapp开发HarmonyOS 5.0旅游应用技术实践
一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架,支持"一次开发,多端部署",可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务,为旅游应用带来…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...
ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...
Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
