当前位置: 首页 > news >正文

java多线程之ThreadLocal详解

ThreadLocal

      • 一、ThreadLocal概述
      • 二、ThreadLocal解决并发时的线程不安全问题
      • 三、ThreadLocal的工作原理

一、ThreadLocal概述

ThreadLocal 是一个线程变量工具类。主要用于将私有线程和该线程存放的副本对象做一个映射,各个线程之间的变量互不干扰,例如A线程和B线程都想使用一个变量,此时就存在竞争资源的问题,而这个变量他可以有多份,此时就可以用ThreadLocal作为变量的管理者 ,不存在多线程隐患.。同时它隐式的可以作为一个线程内部的传递信息的一个工具。
ThreadLocal的特点包括线程本地化存储、简化线程安全编程、避免多线程共享状态等。

二、ThreadLocal解决并发时的线程不安全问题

ThreadLocal从另一个角度来解决线程的并发访问。ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。例如在多线程中都去使用一个对象,但是又希望互不干涉,此时就需要用到ThreadLocal。实现线程间数据的隔离,保证各个线程之间的数据独立存储,同时也能实现某些数据的共享和传递
概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。

三、ThreadLocal的工作原理

ThreadLocal是作为当前线程属性ThreadLocalMap集合中的某一个Entry的key值Entry(threadLocal,value),虽然不同的线程之间threadlocal这个key值是一样,但是不同的线程所拥有的ThreadLocalMap是独一无二的,也就是不同的线程间同一个ThreadLocal(key)对应存储的值(value)不一样,从而到达了线程间变量隔离的目的,但是在同一个线程中这个value变量地址是一样的。

//ThreadLocal中主要使用下面四个方法 get set remove withInitial(初始化方法 相当于 new ThreadLocal() )public void set(T value) {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null) {map.set(this, value);} else {createMap(t, value);}}public T get() {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null) {ThreadLocalMap.Entry e = map.getEntry(this);if (e != null) {@SuppressWarnings("unchecked")T result = (T)e.value;return result;}}return setInitialValue();}private T setInitialValue() {T value = initialValue();Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null)map.set(this, value);elsecreateMap(t, value);return value;}public void remove() {ThreadLocalMap m = getMap(Thread.currentThread());if (m != null) {m.remove(this);}}

当通过 ThreadLocal 的 set 方法设置变量时,实际上是通过当前线程的ThreadLocalMap 将 ThreadLocal 与值关联起来。
当通过 ThreadLocal 的 get 方法获取变量时,实际上是通过当前线程的ThreadLocalMap 查找与之关联的值。
ThreadLocalMap 使用 ThreadLocal 的弱引用作为 key,以防止内存泄漏。当 ThreadLocal 被回收时,对应的映射关系也会被清理。

相关文章:

  • 【Linux详解】进程地址空间
  • 网络爬虫中Xpath的使用方法
  • 【微信小程序开发实战项目】——如何制作一个属于自己的花店微信小程序(1)
  • 深度学习21-30
  • 先导小型工业4.0教学生产线助力制造业技术创新
  • 老年生活照护实训室:探索现代养老服务的奥秘
  • NAS安全存储怎样实现更精细的数据权限管控?
  • Grafana面试题精选和参考答案
  • 【计算机视觉】mmcv库详细介绍
  • sqlmap常用参数及示例
  • 重温react-07(函数注释和useEffect的使用方式)
  • 秋招Java后端开发冲刺——非关系型数据库篇(Redis)
  • SSM OA办公系统19159
  • 使用ECharts实现动态数据可视化的最佳实践
  • 2024年建筑八大员(质量员-土建专业)考试题库。全面提升考试成绩,轻松过级!
  • JS中 map, filter, some, every, forEach, for in, for of 用法总结
  • 《微软的软件测试之道》成书始末、出版宣告、补充致谢名单及相关信息
  • angular2开源库收集
  • Cumulo 的 ClojureScript 模块已经成型
  • Git的一些常用操作
  • scala基础语法(二)
  • spring cloud gateway 源码解析(4)跨域问题处理
  • 第三十一到第三十三天:我是精明的小卖家(一)
  • 后端_MYSQL
  • 精益 React 学习指南 (Lean React)- 1.5 React 与 DOM
  • 前端存储 - localStorage
  • 时间复杂度与空间复杂度分析
  • 适配mpvue平台的的微信小程序日历组件mpvue-calendar
  • 手机app有了短信验证码还有没必要有图片验证码?
  • 协程
  • LevelDB 入门 —— 全面了解 LevelDB 的功能特性
  • ​一文看懂数据清洗:缺失值、异常值和重复值的处理
  • # Kafka_深入探秘者(2):kafka 生产者
  • #07【面试问题整理】嵌入式软件工程师
  • #LLM入门|Prompt#2.3_对查询任务进行分类|意图分析_Classification
  • #QT(QCharts绘制曲线)
  • #Spring-boot高级
  • #在线报价接单​再坚持一下 明天是真的周六.出现货 实单来谈
  • $.type 怎么精确判断对象类型的 --(源码学习2)
  • (动态规划)5. 最长回文子串 java解决
  • (二刷)代码随想录第15天|层序遍历 226.翻转二叉树 101.对称二叉树2
  • (附源码)spring boot网络空间安全实验教学示范中心网站 毕业设计 111454
  • (接口封装)
  • (详细版)Vary: Scaling up the Vision Vocabulary for Large Vision-Language Models
  • (一)C语言之入门:使用Visual Studio Community 2022运行hello world
  • .aanva
  • .NET CF命令行调试器MDbg入门(二) 设备模拟器
  • .NET Framework杂记
  • .net mvc部分视图
  • .NET 使用配置文件
  • .NET/C# 使用 #if 和 Conditional 特性来按条件编译代码的不同原理和适用场景
  • @FeignClient 调用另一个服务的test环境,实际上却调用了另一个环境testone的接口,这其中牵扯到k8s容器外容器内的问题,注册到eureka上的是容器外的旧版本...
  • [ 攻防演练演示篇 ] 利用通达OA 文件上传漏洞上传webshell获取主机权限
  • [ 云计算 | AWS ] AI 编程助手新势力 Amazon CodeWhisperer:优势功能及实用技巧
  • []指针