我的编程空间,编程开发者的网络收藏夹
学习永远不晚

ThreadLocal原理分析及应用场景是怎样的

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

ThreadLocal原理分析及应用场景是怎样的

本篇文章给大家分享的是有关ThreadLocal原理分析及应用场景是怎样的,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。

1. ThreadLocal是什么?有哪些用途?

首先介绍Thread类中属性threadLocals:

ThreadLocal.ThreadLocalMap threadLocals = null;

我们发现Thread并没有提供成员变量threadLocals的设置与访问的方法,那么每个线程的实例threadLocals参数我们如何操作呢?这时我们的主角:ThreadLocal就登场了。

所以有那么一句总结:ThreadLocal是线程Thread中属性threadLocals的管理者。

也就是说我们对于ThreadLocal的get, set,remove的操作结果都是针对当前线程Thread实例的threadLocals存,取,删除操作。类似于一个开发者的任务,产品经理左右不了,产品经理只能通过技术leader来给开发者分配任务。下面再举个栗子,进一步说明他们之间的关系:

ThreadLocal原理分析及应用场景是怎样的

每个人都一张银行卡

每个人每张卡都有一定的余额。

每个人获取银行卡余额都必须通过该银行的管理系统。

每个人都只能获取自己卡持有的余额信息,他人的不可访问。

ThreadLocal原理分析及应用场景是怎样的

映射到我们要说的ThreadLocal

  • card类似于Thread

  • card余额属性,卡号属性等类似于Treadlocal内部属性集合threadLocals

  • cardManager类似于ThreadLocal管理类

那ThreadLocal有哪些应用场景呢?

其实我们无意间已经时时刻刻在使用ThreadLocal提供的便利,如果说多数据源的切换你比较陌生,那么spring提供的声明式事务就再熟悉不过了,我们在研发过程中无时无刻不在使用,而spring声明式事务的重要实现基础就是ThreadLocal,只不过大家没有去深入研究spring声明式事务的实现机制。后面有机会我会给大家介绍spring声明式事务的原理及实现机制。

原来ThreadLocal这么强大,但应用开发者使用较少,同时有些研发人员对于ThreadLocal内存泄漏,等潜在问题,不敢试用,恐怕这是对于ThreadLocal最大的误解,后面我们将会仔细分析,只要按照正确使用方式,就没什么问题。如果ThreadLocal存在问题,岂不是spring声明式事务是我们程序最大的潜在危险吗?

2.ThreadLocal如何使用

为了更直观的体会ThreadLocal的使用我们假设如下场景

  • 我们给每个线程生成一个ID。

  • 一旦设置,线程生命周期内不可变化。

  • 容器活动期间不可以生成重复的ID

我们创建一个ThreadLocal管理类:

ThreadLocal原理分析及应用场景是怎样的

测试程序如下:我们同一个线程不断get,测试id是否变化,同时测试完成后我们就将其释放掉。

ThreadLocal原理分析及应用场景是怎样的

在主程序中我们开启多个线程测试不通线程之间是否会影响

ThreadLocal原理分析及应用场景是怎样的

不出意外我们的结果为:

ThreadLocal原理分析及应用场景是怎样的

结果:确实是不同线程间id不同,相同线程id相同。

3.ThreadLocal原理

①ThreadLocal类结构及方法解析:

ThreadLocal原理分析及应用场景是怎样的

上图可知:ThreadLocal三个方法get, set , remove以及内部类`ThreadLocalMap

②ThreadLocal及Thread之间的关系:

ThreadLocal原理分析及应用场景是怎样的

从这张图我们可以直观的看到Thread中属性threadLocals,作为一个特殊的Map,它的key值就是我们ThreadLocal实例,而value值这是我们设置的值。

③ThreadLocal的操作过程:

我们以get方法为例:

ThreadLocal原理分析及应用场景是怎样的

其中getMap(t)返回的就上当前线程的threadlocals,如下图,然后根据当前ThreadLocal实例对象作为key获取ThreadLocalMap中的value,如果首次进来这调用setInitialValue()

ThreadLocal原理分析及应用场景是怎样的

ThreadLocal原理分析及应用场景是怎样的

set的过程也类似:

ThreadLocal原理分析及应用场景是怎样的

注意:ThreadLocal中可以直接t.threadLocals是因为ThreadThreadLocal在同一个包下,同样Thread可以直接访问ThreadLocal.ThreadLocalMap threadLocals = null;来进行声明属性。

4.ThreadLocal使用有哪些坑及注意事项

我经常在网上看到骇人听闻的标题,ThreadLocal导致内存泄漏,这通常让一些刚开始对ThreadLocal理解不透彻的开发者,不敢贸然使用。越不用,越陌生。这样就让我们错失了更好的实现方案,所以敢于引入新技术,敢于踩坑,才能不断进步。

我们来看下为什么说ThreadLocal会引起内存泄漏,什么场景下会导致内存泄漏?

先回顾下什么叫内存泄漏,对应的什么叫内存溢出

  • ①Memory overflow:内存溢出,没有足够的内存提供申请者使用。

  • ②Memory leak:内存泄漏,程序申请内存后,无法释放已申请的内存空间,内存泄漏的堆积终将导致内存溢出。

显然是TreadLocal在不规范使用的情况下导致了内存没有释放。

ThreadLocal原理分析及应用场景是怎样的

红框里我们看到了一个特殊的类WeakReference,同样这个类,应用开发者也同样很少使用,这里简单介绍下吧

类型回收时间应用场景
强引用一直存活,除非GC Roots不可达所有程序的场景,基本对象,自定义对象等
软引用内存不足时会被回收一般用在对内存非常敏感的资源上,用作缓存的场景比较多,例如:网页缓存、图片缓存
弱引用只能存活到下一次GC前生命周期很短的对象,例如ThreadLocal中的Key。
虚引用随时会被回收, 创建了可能很快就会被回收可能被JVM团队内部用来跟踪JVM的垃圾回收活动

既然WeakReference在下一次gc即将被回收,那么我们的程序为什么没有出问题呢?

  • ①所以我们测试下弱引用的回收机制:

ThreadLocal原理分析及应用场景是怎样的

这一种存在强引用不会被回收。

ThreadLocal原理分析及应用场景是怎样的

这里没有强引用将会被回收。

上面演示了弱引用的回收情况,下面我们看下ThreadLocal的弱引用回收情况。

  • ThreadLocal的弱引用回收情况

ThreadLocal原理分析及应用场景是怎样的

如上图所示,我们在作为key的ThreadLocal对象没有外部强引用,下一次gc必将产生key值为null的数据,若线程没有及时结束必然出现,一条强引用链

Threadref–>Thread–>ThreadLocalMap–>Entry,所以这将导致内存泄漏。

下面我们模拟复现ThreadLocal导致内存泄漏:

为了效果更佳明显我们将我们的treadlocals的存储值value设置为1万字符串的列表:

class ThreadLocalMemory {    // Thread local variable containing each thread's ID    public ThreadLocal<List<Object>> threadId = new ThreadLocal<List<Object>>() {        @Override        protected List<Object> initialValue() {            List<Object> list = new ArrayList<Object>();            for (int i = 0; i < 10000; i++) {                list.add(String.valueOf(i));            }            return list;        }    };    // Returns the current thread's unique ID, assigning it if necessary    public List<Object> get() {        return threadId.get();    }    // remove currentid    public void remove() {        threadId.remove();    }}

测试代码如下:

public static void main(String[] args)            throws InterruptedException {        //  为了复现key被回收的场景,我们使用临时变量        ThreadLocalMemory memeory = new ThreadLocalMemory();        // 调用        incrementSameThreadId(memeory);        System.out.println("GC前:key:" + memeory.threadId);        System.out.println("GC前:value-size:" + refelectThreadLocals(Thread.currentThread()));        // 设置为null,调用gc并不一定触发垃圾回收,但是可以通过java提供的一些工具进行手工触发gc回收。        memeory.threadId = null;        System.gc();        System.out.println("GC后:key:" + memeory.threadId);        System.out.println("GC后:value-size:" + refelectThreadLocals(Thread.currentThread()));        // 模拟线程一直运行        while (true) {        }    }

此时我们如何知道内存中存在memory leak呢?

我们可以借助jdk提供的一些命令dump当前堆内存,命令如下:

jmap -dump:live,format=b,file=heap.bin <pid>

然后我们借助MAT可视化分析工具,来查看对内存,分析对象实例的存活状态:

ThreadLocal原理分析及应用场景是怎样的

ThreadLocal原理分析及应用场景是怎样的

首先打开我们工具提示我们的内存泄漏分析:

ThreadLocal原理分析及应用场景是怎样的

这里我们可以确定的是ThreadLocalMap实例的Entry.value是没有被回收的。

最后我们要确定Entry.key是否还在?打开Dominator Tree,搜索我们的ThreadLocalMemory,发现并没有存活的实例。

ThreadLocal原理分析及应用场景是怎样的

ThreadLocal原理分析及应用场景是怎样的

以上我们复现了ThreadLocal不正当使用,引起的内存泄漏。demo在这里。

所以我们总结了使用ThreadLocal时会发生内存泄漏的前提条件:

  • ThreadLocal引用被设置为null,且后面没有set,get,remove操作。

  • ②线程一直运行,不停止。(线程池)

  • ③触发了垃圾回收。(Minor GC或Full GC)

我们看到ThreadLocal出现内存泄漏条件还是很苛刻的,所以我们只要破坏其中一个条件就可以避免内存泄漏,单但为了更好的避免这种情况的发生我们使用ThreadLocal时遵守以下两个小原则:

  • ①ThreadLocal申明为private static final。
    Private与final 尽可能不让他人修改变更引用,
    Static 表示为类属性,只有在程序结束才会被回收。

  • ②ThreadLocal使用后务必调用remove方法。
    最简单有效的方法是使用后将其移除。

以上就是ThreadLocal原理分析及应用场景是怎样的,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注编程网行业资讯频道。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

ThreadLocal原理分析及应用场景是怎样的

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

ThreadLocal原理分析及应用场景是怎样的

本篇文章给大家分享的是有关ThreadLocal原理分析及应用场景是怎样的,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。1. ThreadLocal是什么?有哪些用途?首先介绍
2023-06-22

ThreadLocal的原理和使用场景是什么

ThreadLocal是Java中的一个类,用于在多线程环境中实现线程内部的数据共享。它提供了一个线程局部变量,每个线程都可以独立地改变该变量的值,而不会影响其他线程的该变量的值。ThreadLocal的原理是通过为每个线程创建一个独立的变
2023-09-12

ssl原理及应用场景是什么

SSL(Secure Sockets Layer)是一种加密协议,用于保护在互联网上传输的数据安全。它使用公钥加密来保护数据的机密性和完整性,以及数字签名来验证数据的真实性。SSL通常用于Web浏览器和服务器之间的安全通信,以确保数据传输过
2023-06-12

MySQL事务的原理及应用场景

MySQL事务的原理及应用场景在数据库系统中,事务是一组SQL操作的集合,这些操作要么全部成功执行,要么全部失败回滚。MySQL作为一种常用的关系型数据库管理系统,支持事务的特性,能够确保数据库中的数据在一致性、隔离性、持久性和原子性方面
MySQL事务的原理及应用场景
2024-03-02

ZooKeeper核心原理及应用场景是什么

这篇文章将为大家详细讲解有关ZooKeeper核心原理及应用场景是什么,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。为什么会有ZooKeeper 我们知道要写一个分布式应用是非常困难的,主要
2023-06-02

Javascript闭包使用场景的原理分析

这篇文章给大家分享的是有关Javascript闭包使用场景的原理分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、闭包Javascript中,只有函数内部的子函数才能读取局部变量,闭包就是能够读取其他函数内部
2023-06-25

PHP开发缓存的原理及应用场景

PHP开发缓存的原理及应用场景,需要具体代码示例随着互联网技术的发展,PHP已成为广泛应用的开发语言之一。在PHP开发中,使用缓存是一种常见的优化技术,可以减少数据库查询次数,缩短响应时间,提升应用性能。缓存原理缓存是一种将数据存储在内存中
PHP开发缓存的原理及应用场景
2023-11-08

vue中filter的应用场景是怎样的

本篇文章给大家分享的是有关vue中filter的应用场景是怎样的,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。filter一般用于过滤某些值,比如我这个字段是空,可是我想在前端
2023-06-25

MySQL 的 SSL 连接优势及应用场景分析

随着互联网的高速发展,数据传输的安全性也成为各个行业关注的焦点。在数据库管理系统中,MySQL是广泛使用的一种关系型数据库,其在数据存储和管理方面具有优势。然而,在数据传输过程中,可能存在安全隐患,因此,MySQL提供了SSL连接,以提高数
2023-10-22

阿里云ECS的应用场景及优势分析

阿里云ECS(ElasticComputeService)是阿里云提供的一种弹性计算服务,它可以满足各种不同应用场景下的需求。本文将介绍阿里云ECS的应用场景,并分析其优势。应用场景一:Web应用服务器阿里云ECS可以作为Web应用服务器来运行网站或应用程序。通过使用阿里云ECS,您可以快速部署和管理您的Web应
阿里云ECS的应用场景及优势分析
2024-01-22

turtle库的安装以及原理分析是怎样的

这篇文章给大家介绍turtle库的安装以及原理分析是怎样的,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。turtle库是Python中一个很流行的绘图函数库,主要是依据坐标轴来绘制图像,画笔则是一只小海龟,通过控制海龟
2023-06-02

PHP CLI与CGI的区别及应用场景比较分析

PHP CLI与CGI的区别及应用场景比较分析PHP是一种流行的服务器端脚本语言,通常用于创建动态网页内容。在PHP中,有两种主要的执行方式:命令行界面(CLI)和通用网关接口(CGI)。虽然它们都可以执行PHP脚本,但它们在功能和应用场
PHP CLI与CGI的区别及应用场景比较分析
2024-03-10

Docker中Dockerfile多阶段构建原理及使用场景的示例分析

小编给大家分享一下Docker中Dockerfile多阶段构建原理及使用场景的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!老版本Docker中为什么不支持多个 FROM 指令在17.05版本之前的Docker,只
2023-06-04

Java中ThreadLocal的原理是什么及怎么使用

这篇文章主要介绍“Java中ThreadLocal的原理是什么及怎么使用”,在日常操作中,相信很多人在Java中ThreadLocal的原理是什么及怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Jav
2023-07-06

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录