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

java ThreadLocal 原理说明

准备工作

创建一个共享变量ThreadLocal

再创建一个向共享变量ThreadLocal 中赋值的线程

再创建一个从共享变量ThreadLocal 中取值的线程

如下图所示:tl为共享变量ThreadLocal

TestThreadForSet 为赋值线程;TestThreadForGet 为取值线程,

为保证赋值线程先于取值线程执行,中间加入了等待2秒

运行结果:

如果ThreadLocal 为普通的共享变量,那么取到的值一定为赋值线程中设置的值。

然而:实际运行结果如下:

下面来说明为什么会这样:

首先我们需要了解赋值线程赋值的时候,把值存储到哪里去了?

我们跟踪下ThreadLocal的set方法

1:首先获取当前线程,然后执行了getMap方法,参数为当前线程,我们下面看getMap方法

这里是重点,直接返回的是线程内部的实例变量threadLocals,注意这里是线程内部的实例变量,也就是说实际运行过程中每个线程都有一个threadLocals变量,这个变量的类型ThreadLocalMap。如下图

2:getMap执行完后,我们再返回到set方法中,这个时候会判断map是否为空,因为我们是第一次赋值,所以map肯定为null

,然后执行createMap方法,方法参数为当前线程对象,以及你要赋值的变量。

3:我们看到这里给线程的threadLocals变量赋值了一个新的对象,这里再次声明一下,threadLocals是当前线程的实例变量,每个线程不共享,即如果有10个线程那么就会有10个threadLocals变量,每个线程一个。下面我们看new ThreadLocalMap(this, firstValue);做了什么,这个构造方法中第一个参数为this,这个this指向的是threadLocal变量,也就是在main方法中声明的变量tl,看下图

注意跟上面的threadLocals区分开;这个构造方法中第二个参数为你赋值的内容。

4:上图中构造方法里的内容,这里总结成一句话就是 以Threadlocal(这里没有s)变量对象为key,以你赋值的内容为value放到ThreadLocalMap中。

总结一下,下图中这几条语句的主要逻辑是,首先获取当前线程中的一个实例变量map,如果获取到的map为空,那么就创建一个map,并把ThreadLocal变量作为key,自定义赋值内容为value放到map中,如果不为空,那就直接放了,相信很多同学都写过这样的逻辑。

到此为止,我们讲了set方法的逻辑。下面我们看下get方法的逻辑,get方法的逻辑其实就是到当前线程的threadLocals变量(ThreadLocalMap类型)里找this为key对应的value,this变量指的是ThreadLocal共享变量tl。注意这里又提到了当前线程。

我们用一张图总结一下上面的内容

相关文章:

  • nexus 私服 提示磁盘空间不足
  • 关于String常量池的理解
  • java中lambda表达式双冒号::的使用
  • java web 解决cors 跨域问题
  • java lambda 对list实现分组(groubby);并将对象的部分属性作为List对象,然后返回list中的第一个值
  • win10 mysql 主从复制(异步复制)配置
  • TCC java 案例
  • spring-cloud-sleuth链路信息中增加自定义属性
  • spring 替换字符串中的配置信息
  • dolphinscheduler1.3版本源码分析---API模块
  • dolphinscheduler1.3版本源码分析---MASTER模块
  • gradle 作为编译工具 lombok 死活不生效解决
  • java lambda groupingby 结果的value为对象的一个属性
  • class.getTypeParameters()方法
  • flatmap使用
  • avalon2.2的VM生成过程
  • chrome扩展demo1-小时钟
  • ES6语法详解(一)
  • python docx文档转html页面
  • RedisSerializer之JdkSerializationRedisSerializer分析
  • SpringBoot几种定时任务的实现方式
  • UMLCHINA 首席专家潘加宇鼎力推荐
  • 读懂package.json -- 依赖管理
  • 短视频宝贝=慢?阿里巴巴工程师这样秒开短视频
  • 简析gRPC client 连接管理
  • 前端
  • 入职第二天:使用koa搭建node server是种怎样的体验
  • 手写双向链表LinkedList的几个常用功能
  • 一天一个设计模式之JS实现——适配器模式
  • UI设计初学者应该如何入门?
  • Unity3D - 异步加载游戏场景与异步加载游戏资源进度条 ...
  • 正则表达式-基础知识Review
  • ###C语言程序设计-----C语言学习(3)#
  • (4)通过调用hadoop的java api实现本地文件上传到hadoop文件系统上
  • (delphi11最新学习资料) Object Pascal 学习笔记---第2章第五节(日期和时间)
  • (LNMP) How To Install Linux, nginx, MySQL, PHP
  • (附源码)基于ssm的模具配件账单管理系统 毕业设计 081848
  • (收藏)Git和Repo扫盲——如何取得Android源代码
  • (原创)Stanford Machine Learning (by Andrew NG) --- (week 9) Anomaly DetectionRecommender Systems...
  • (转) SpringBoot:使用spring-boot-devtools进行热部署以及不生效的问题解决
  • .CSS-hover 的解释
  • .Family_物联网
  • .NET 5种线程安全集合
  • .Net CF下精确的计时器
  • .NET HttpWebRequest、WebClient、HttpClient
  • .Net(C#)常用转换byte转uint32、byte转float等
  • .NET处理HTTP请求
  • @SuppressWarnings注解
  • [ 英语 ] 马斯克抱水槽“入主”推特总部中那句 Let that sink in 到底是什么梗?
  • [APUE]进程关系(下)
  • [AR]Vumark(下一代条形码)
  • [BUG]Datax写入数据到psql报不能序列化特殊字符
  • [C#]无法获取源 https://api.nuge t.org/v3-index存储签名信息解决方法
  • [C++基础]-入门知识
  • [codevs 1515]跳 【解题报告】