【并发】第二篇 ThreadLocal详解

导航

    • 一. ThreadLocal 简介
    • 二. ThreadLocal 源码解析
      • 1. get
      • 2. set
      • 3 .remove
      • 4. initialValue
    • 三. ThreadLocalMap 源码分析
      • 1. 构造方法
      • 2. getEntry()
      • 3. set()
      • 4. resize()
      • 5. expungeStaleEntries()
      • 6. cleanSomeSlots()
      • 7. nextIndex()
      • 8. remove()
      • 9. 总结ThreadLocalMap
    • 四. 内存泄漏
      • 1. 产生原理分析
      • 2. 解决方式
    • 五. ThreadLocal 常见的应用场景
      • 1. 数据库连接
      • 2. 事务管理
      • 3. 用户身份认证
      • 4. 线程安全的计数器

在这里插入图片描述

管网上的介绍是这样:
This class provides thread-local variables. These variables differ from their normal counterparts in that each thread that accesses one (via its get or set method) has its own, independently ini alized copy of the variable. ThreadLocal instances are typically private sta c fields in classes that wish to associate state with a thread (e.g., a user ID or Transac on ID).
此类提供线程局部变量。这些变量与正常的对应变量的不同之处在于,每个访问一个变量(通过其get或set方法)的线程都有自己的、独立初始化的变量副本。ThreadLocal实例通常是类中的私有静态字段,这些字段希望将状态与线程(例如,用户ID或Transac-on ID)相关联。

一. ThreadLocal 简介

ThreadLocal 是 Java 中的一个类,它提供了线程局部变量的机制。线程局部变量是指每个线程都有自己独立的变量副本,线程之间互不影响。
通常情况下,如果多个线程同时访问一个共享变量,需要进行同步来保证线程安全,如Synchronized。而使用 ThreadLocal 也可以避免线程安全问题,因为每个线程都拥有自己的变量副本,且可以独立地操作自己的变量副本,而不会影响其他线程的副本。线程之间的变量副本互不干扰,保证了线程安全。
在这里插入图片描述

二. ThreadLocal 源码解析

ThreadLocal 类接口很简单,有4个核心内部成员方法

1. get

返回当前线程所对应的线程局部变量

public T get() {// 获取当前线程Thread对象Thread t = Thread.currentThread();// 获取当前线程的ThreadLocalMapThreadLocalMap map = getMap(t);if (map != null) {// 通过ThreadLocal对象获取变量副本ThreadLocalMap.Entry e = map.getEntry(this);if (e != null) {@SuppressWarnings("unchecked")// 返回变量副本T result = (T)e.value;return result;}}// 如果ThreadLocalMap为空,或者变量副本未找到,则调用initialValue()方法初始化变量副本// 返回一个nullreturn setInitialValue();
}

ThreadLocalMap 虽然是ThreadLocal的静态内部类, 但在Thread类中也有一个这样类型成员变量,也就是说真正实例化ThreadLocalMap是在Thread类中实现的, 所以getMap()方法实际上返回的是Thread类中成员变量

ThreadLocalMap getMap(Thread t) {return t.threadLocals;}

2. set

设置当前线程的线程局部变量的值

public void set(T value) {// 获取当前线程Thread对象Thread t = Thread.currentThread();// 通过Thread对象获取ThreadLocalMap对象ThreadLocalMap map = getMap(t);if (map != null)// 如果ThreadLocalMap对象存在,则直接设置变量副本map.set(this, value); else// 如果ThreadLocalMap对象不存在,则创建一个新的ThreadLocalMap对象,并设置变量副本createMap(t, value);}

3 .remove

将当前线程局部变量的值删除, 目的是为了减少内存的占用, 避免内存泄漏
该方法是 JDK 5.0 新增的方法。需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收, 所以显式调用该方法清除线程的局部变量并不是必须的操作, 但它可以加快内存回收的速度。

public void remove() {//获取当前线程的ThreadLocalMap ThreadLocalMap m = getMap(Thread.currentThread());if (m != null)//this指当前ThreadLocal实例//ThreadLocalMap中的Entry[]数组中,删除Entry[]数组中使用当前ThreadLocal实例作为key的Entrym.remove(this);}

4. initialValue

返回该线程局部变量的初始值
该方法是一个 protected 的方法,显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法,在线程第1次调用 get() 或 set(Object)时才执行,并且仅执行1次。ThreadLocal 中的缺省实现直接返回一 个null。

protected T initialValue() {return null;
}

三. ThreadLocalMap 源码分析

每个线程所拥有的变量的副本数是不定的,有些线程可能有一个,有些线程可能有 2个甚至更多, 则线程内部存放变量副本需要一个容器, 而且容器要支持快速存取, 所以在每个线程内部都可以持有一个 Map 来支持多个变量 副本,这个Map被称为ThreadLocalMap。

static class ThreadLocalMap {/*** Entry数组,用于存储ThreadLocal与变量副本之间的映射关系*/static class Entry extends WeakReference<ThreadLocal<?>> {//变量副本Object value;//key-ThreadLocal实例  value-变量副本Entry(ThreadLocal<?> k, Object v) {super(k);value = v;}}// 数组的大小必须为 2 的次幂private static final int INITIAL_CAPACITY = 16;// Entry对象数组,用于存储ThreadLocal与变量副本之间的映射关系private Entry[] table;// 记录当前数组中实际存在元素个数private int size = 0;// ThreadLocalMap的阈值,当size超过该值时进行扩容操作

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

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

相关文章

python习题小练习(挑战全对)

1. (单选题)Python 3.0版本正式发布的时间&#xff1f; A. 1991B. 2000C. 2008D. 1989 2. (单选题)以下关于Python语言中“缩进”说法正确的是&#xff1a; A. 缩进在程序中长度统一且强制使用B. 缩进是非强制的&#xff0c;仅为了提高代码可读性C. 缩进可以用在任何语句之后…

超文本传输协议HTTP

HTTP协议 在网络通信中&#xff0c;我们可以自己进行定制协议&#xff0c;但是也有许多已经十分成熟的应用层协议&#xff0c;比如我们下面说的HTTP协议。 HTTP协议简介 HTTP&#xff08;Hyper Text Transfer Protocol&#xff09;协议又叫做超文本传输协议&#xff0c;是一…

带你学习现代C++并发编程

通过对C并发编程的理解&#xff0c;我总结了相关的文档&#xff0c;有需要的可以关注我公众号&#xff0c;并给我留言&#xff01; 这是目录

专升本-现代通信技术5G

现代通信技术 什么是通信&#xff1a; 人与人&#xff0c;人与自然之间通过某种行为或者媒体介质进行信息交流和传递 通信的基本要素&#xff1a; 信源 ----信道&#xff08;噪音-干扰&#xff09;-----信宿 通信技术是什么&#xff1f; 研究从信息的源头到信息的目的地整…

Cookie/Session

1.Cookie HTTP 协议自身是属于 "无状态" 协议. "无状态" 的含义指的是: 默认情况下 HTTP 协议的客户端和服务器之间的这次通信, 和下次通信之间没有直接的联系. 但是实际开发中, 我们很多时候是需要知道请求之间的关联关系的. 例如登陆网站成功后, 第二…

创建数据库管理账户以及授权

一、创建数据酷管理账户命令 为了保障数据库系统的安全性&#xff0c;以及让 其他用户协同管理数据库&#xff0c;可以在MariaDB数据库管理系统中为他们创建多个专用的数据库管理账户&#xff0c;然后再分配合理的权限&#xff0c;以满足他们的工作需求. 使用root管理员 登录…

机器学习模型——SVM(支持向量机)

基本概念&#xff1a; Support Vector Machine &#xff08;支持向量机&#xff09;: 支持向量&#xff1a;支持或支撑平面上把两类类别划分开来的超平面的向量点。 机&#xff1a;一个算法 SVM是基于统计学习理论的一种机器学习方法。简单地说&#xff0c;就是将数据单元…

自定义类型(二)结构体位段,联合体,枚举

这周一时兴起&#xff0c;想写两篇文章来拿个卷吧&#xff0c;今天也是又来写一篇博客了&#xff0c;也是该结束自定义类型的学习与巩固了。 常常会回顾努力的自己&#xff0c;所以要给自己的努力留下足迹。 为今天努力的自己打个卡&#xff0c;留个痕迹吧 2024.03.30 小闭…

Mybatis在SpringBoot中是如何被加载执行

首先依赖于springboot的自动装配EnableAutoConfiguration注解&#xff0c;这个注解最终帮助我们读取mybatis-spring-boot-autoconfigure-x.x.x.jar中的META-INF\spring.factories配置类&#xff1a; org.springframework.boot.autoconfigure.EnableAutoConfiguration\ org.myb…

Mysql数据库——阻塞语句查询与分析

目录 前言 阻塞语句查询与分析 Show Processlist——查看每个与数据库连接的session状态 非Sleeping状态进程数 执行时间较长进程号 查看当前运行的所有事务 当前锁 被blocking阻塞的事务数 数据库连接数 查看锁状态 正在被使用的表 前言 MySQL阻塞是指并发访问时&…

LInux|命令行参数|环境变量

LInux|命令行参数|环境变量 命令行参数main的参数之argc&#xff0c;argv几个小知识<font color#0099ff size 5 face"黑体">1.子进程默认能看到并访问父进程的数据<font color#4b0082 size 5 face"黑体">2.命令行创建的程序父进程都是bash 环…

微分方程错题本

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

【图像超分】论文精读:Image Super-Resolution Using Dense Skip Connections(SRDenseNet)

第一次来请先看这篇文章:【超分辨率(Super-Resolution)】关于【超分辨率重建】专栏的相关说明,包含专栏简介、专栏亮点、适配人群、相关说明、阅读顺序、超分理解、实现流程、研究方向、论文代码数据集汇总等) 文章目录 前言Abstract1. Introduction2. Related work2.1. S…

解释TCP和UDP之间的区别

解释TCP和UDP之间的区别 TCP&#xff08;传输控制协议&#xff09;和UDP&#xff08;用户数据报协议&#xff09;是两种在网络中广泛使用的传输层协议&#xff0c;它们各自具有独特的特点和适用场景。下面将详细解释TCP和UDP之间的区别&#xff0c;并从多个维度进行对比。 连…

设计模式(4):建造者模式

一.场景 我们要建造一个复杂的产品,比如手机、电脑、汽车。这个复杂的产品的创建。有这样一个问题需要处理&#xff1a; 装配这些子组件是不是有个步骤问题&#xff1f; 实际开发中&#xff0c;我们所需要的对象构建时&#xff0c;也非常复杂&#xff0c;有很多步骤需要处理时…

【Qt】:信号与槽(二)

信号与槽 一.带参数的信号和槽二.信号与槽的多对多连接三.信号与槽的断开四.lamda表达式定义槽函数 一.带参数的信号和槽 Qt的信号和槽也⽀持带有参数,同时也可以⽀持重载.此处我们要求,信号函数的参数列表要和对应连接的槽函数参数列表⼀致.&#xff08;一致指的是类型一致&a…

【算法笔记】 树形DP算法总结

定义&#xff1a;树形DP也叫树状DP&#xff0c;即在树上进行的DP&#xff0c;是DP中较为复杂一类 1&#xff1a;主体 即like拓扑排序&#xff0c;从叶子节点向上更新其父节点&#xff0c;从而进行dp&#xff0c;确保先更新的子节点去更新其父节点&#xff0c;一般使用dfs形式…

mysql安装遇到的问题

最近mysql安装遇到了许多问题 这个界面是下载器界面&#xff0c;reconfigure是重新配置这个版本&#xff0c;要新安装要点add 进入这个界面选择对应的版本下载

面试题库二

1、简述TCP/IP的三次握手和四次挥手 TCP&#xff08;Transmission Control Protocol&#xff09;是一种可靠的、面向连接的传输层协议&#xff0c;用于在网络中传输数据。在建立连接和断开连接时&#xff0c;TCP 使用了三次握手和四次挥手来确保通信的可靠性和正确性。 三次握手…

【C语言】作用域规则

任何一种编程中&#xff0c;作用域是程序中定义的变量所存在的区域&#xff0c;超过该区域变量就不能被访问。C语言中有三个地方可以声明变量&#xff1a; 在函数或块内部的局部变量在所有函数外部的全局变量在形式参数的函数参数定义中 局部变量 在某个函数或块的内部声明的…