先了解一下ThreadLocal类提供的几个方法:

public T get() { }
public void set(T value) { }
public void remove() { }
protected T initialValue() { }

get()方法是用来获取ThreadLocal在当前线程中保存的变量副本,set()用来设置当前线程中变量的副本,remove()用来移除当前线程中变量的副本,initialValue()是一个protected方法,一般是用来在使用时进行重写的,它是一个延迟加载方法,下面会详细说明。
首先我们来看一下ThreadLocal类是如何为每个线程创建一个变量的副本的。

先看下get方法的实现:

第一句是取得当前线程,然后通过getMap(t)方法获取到一个map,map的类型为ThreadLocalMap。然后接着下面获取到<key,value>键值对,注意这里获取键值对传进去的是  this,而不是当前线程t。

如果获取成功,则返回value值。   如果map为空,则调用setInitialValue方法返回value。
我们上面的每一句来仔细分析:

首先看一下getMap方法中做了什么:

可能大家没有想到的是,在getMap中,是调用当期线程t,返回当前线程t中的一个成员变量threadLocals。
那么我们继续取Thread类中取看一下成员变量threadLocals是什么:

实际上就是一个ThreadLocalMap,这个类型是ThreadLocal类的一个内部类,我们继续取看ThreadLocalMap的实现:

可以看到ThreadLocalMap的Entry继承了WeakReference,并且使用ThreadLocal作为键值。
然后再继续看setInitialValue方法的具体实现:

很容易了解,就是如果map不为空,就设置键值对,为空,再创建Map,看一下createMap的实现:

至此,可能大部分朋友已经明白了ThreadLocal是如何为每个线程创建变量的副本的:
首先,在每个线程Thread内部有一个ThreadLocal.ThreadLocalMap类型的成员变量threadLocals,这个threadLocals就是用来存储实际的变量副本的,键值为当前ThreadLocal变量,value为变量副本(即T类型的变量)。

初始时,在Thread里面,threadLocals为空,当通过ThreadLocal变量调用get()方法或者set()方法,就会对Thread类中的threadLocals进行初始化,并且以当前ThreadLocal变量为键值,以ThreadLocal要保存的副本变量为value,存到threadLocals。

测试输出的日志:

调用get方法时,当前线程共享变量没有设置,调用initialValue获取默认值!
线程IntegerTask1: 0
调用get方法时,当前线程共享变量没有设置,调用initialValue获取默认值!
线程IntegerTask2: 0
调用get方法时,当前线程共享变量没有设置,调用initialValue获取默认值!
调用get方法时,当前线程共享变量没有设置,调用initialValue获取默认值!
线程StringTask1: a
线程StringTask2: a
线程StringTask1: aa
线程StringTask2: aa
线程IntegerTask1: 1
线程IntegerTask2: 1
线程StringTask1: aaa
线程StringTask2: aaa
线程IntegerTask2: 2
线程IntegerTask1: 2
线程StringTask2: aaaa
线程StringTask1: aaaa
线程IntegerTask2: 3
线程IntegerTask1: 3
线程StringTask1: aaaaa
线程StringTask2: aaaaa
调用get方法时,当前线程共享变量没有设置,调用initialValue获取默认值!
线程IntegerTask2: 0
调用get方法时,当前线程共享变量没有设置,调用initialValue获取默认值!
线程IntegerTask1: 0

从测试输出的日志可以看出:

ThreadLocalMap 是每一个线程内部自带的容器,用来存储共享对象的,其map的key是Threadlocal对象。ThreadLocal new出来一个对象的时候,同时又调用set 设置共享对象的时候,那么ThreadlocalMap 会在set 方法中创建和初始化。然后将当前的threadLocal 作为key,threadLocal 中要set的共享对象作为value存储到ThreadlocalMap 中。

可见ThreadlocalMap 存储的共享对象只是在set的时候保证数据对象是一致的,因为threadLocal 设置的共享是同一个对象。

threadLocal 说白了就是对象的共享,想想我们有很对的实现方式,比如static,比如单例的gets,sets。

最常见的ThreadLocal使用场景为 用来解决 数据库连接、Session管理等。

Thread 中 ThreadLocal 源码解读相关推荐

  1. ThreadLocal源码解读 侵立删

    转自:http://www.cnblogs.com/micrari/p/6790229.html 1. 背景 ThreadLocal源码解读,网上面早已经泛滥了,大多比较浅,甚至有的连基本原理都说的很 ...

  2. Fabric中PBFT源码解读——Checkpoint机制

    文章目录 1. 写在前面 1.1 前置阅读 1.2 对TestCheckpoint函数的测试 2. 对TestCheckpoint函数运行流程的解读 2.1 Checkpoint和Water mark ...

  3. Fabric中PBFT源码解读 (3)

    文章目录 5. Preprepare消息的接收以及Prepare消息的发送 6. Prepare消息的接收以及Commit消息的发送 5. Preprepare消息的接收以及Prepare消息的发送 ...

  4. spark源码解读3之RDD中top源码解读

    更多代码请见:https://github.com/xubo245/SparkLearning spark源码解读系列环境:spark-2.0.1 (20161103github下载版) 1.理解 输 ...

  5. mybatis plus 中 EntityWrapper源码解读

    mybatis plus内置了好多CRUD,其中 EntityWrapper这个类就是. 这个类是mybatis plus帮我们写好的好多接口,就如同我们在dao层写好方法在xml中实现一样. 那么这 ...

  6. pytorch中SGD源码解读

    调用方法: torch.optim.SGD(params, lr=<required parameter>, momentum=0, dampening=0, weight_decay=0 ...

  7. Hive中lateral view的应用到源码解读

    对于从事大数据开发的同学,经常会应用到explode(炸裂函数)和lateral view(侧输出流). Explode(炸裂函数) 参数必须是array或者map格式(通常跟split函数使用): ...

  8. ios html zfplayer,【iOS】ZFPlayer源码解读中

    前言 本篇继ZFPlayer源码解读基础之上,主要解析说明控制层与播放器,因为在上篇文章至现在并未提及丝毫关于这两个类业务的实现. 首先说下这两个类各自的职责. 控制层:主要负责响应与用户之间的交互, ...

  9. Java并发编程之ThreadLocal源码分析

    1 一句话概括ThreadLocal   什么是ThreadLocal?顾名思义:线程本地变量,它为每个使用该对象的线程创建了一个独立的变量副本. 2 ThreadLocal使用场景   用一句话总结 ...

最新文章

  1. Gin源码解析和例子——路由
  2. 局域网伪造源地址DDoS***解决方法
  3. java的log4j的xml配置_Log4j配置实例(log4j.xml)
  4. 八十七、探究最短路问题:Dijkstra算法
  5. Select 可编辑 - 完美支持各大主流浏览器
  6. 优启通怎么重装系统win10_重装系统失败?小编教你安全给神舟战神GX9 Pro重装win10系统方法...
  7. 织梦dede企业律师事务所网模板源码
  8. Unity3d官方测试插件学习-单元测试,集成测试
  9. NLP最新趋势,7个主流业务场景!
  10. halcon学习之边缘检测
  11. 抖音python上的代码_抖音代码舞python实例代码
  12. matlab 冒泡排序函数,MATLAB实现冒泡排序算法
  13. 获取钉钉考勤机的打卡记录并且解析
  14. 重学 statistics, Cha10 Inference About Means and Proportions with Two Populations
  15. 互联网日报 | 6月8日 星期二 | 华为30亿成立数字能源公司;阿里明星直播业务“天猫星选”上线;苹果WWDC 2021开幕...
  16. 绝不要用的 Linux 命令 !
  17. PC端浏览器定位(纯前端)
  18. JAVAEE和项目开发——JSP详解
  19. Android的Activity之生命周期
  20. 【kaggle】特征工程 trick

热门文章

  1. hbase的shell客户端中不同符号的含义
  2. 神经网络中,正则化L1与L2的区别、如何选择以及代码验证
  3. 测试人员如何使用浏览器的f12_测试过程中如何快速定位一个bug
  4. 线上服务器登记的要点
  5. PLSQL Developer 运用Profiler 分析存储过程性能
  6. SQL Server 数据库关键知识点详解(优秀经典)
  7. linux下的struct sigaction
  8. SecureCRT登陆Centos 6.4乱码问题
  9. 【windows8开发】C++开发WinRT组件和JS调用
  10. NetBeans 时事通讯(刊号 # 134 - Jan 25, 2011)