Thread 中 ThreadLocal 源码解读
先了解一下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 源码解读相关推荐
- ThreadLocal源码解读 侵立删
转自:http://www.cnblogs.com/micrari/p/6790229.html 1. 背景 ThreadLocal源码解读,网上面早已经泛滥了,大多比较浅,甚至有的连基本原理都说的很 ...
- Fabric中PBFT源码解读——Checkpoint机制
文章目录 1. 写在前面 1.1 前置阅读 1.2 对TestCheckpoint函数的测试 2. 对TestCheckpoint函数运行流程的解读 2.1 Checkpoint和Water mark ...
- Fabric中PBFT源码解读 (3)
文章目录 5. Preprepare消息的接收以及Prepare消息的发送 6. Prepare消息的接收以及Commit消息的发送 5. Preprepare消息的接收以及Prepare消息的发送 ...
- spark源码解读3之RDD中top源码解读
更多代码请见:https://github.com/xubo245/SparkLearning spark源码解读系列环境:spark-2.0.1 (20161103github下载版) 1.理解 输 ...
- mybatis plus 中 EntityWrapper源码解读
mybatis plus内置了好多CRUD,其中 EntityWrapper这个类就是. 这个类是mybatis plus帮我们写好的好多接口,就如同我们在dao层写好方法在xml中实现一样. 那么这 ...
- pytorch中SGD源码解读
调用方法: torch.optim.SGD(params, lr=<required parameter>, momentum=0, dampening=0, weight_decay=0 ...
- Hive中lateral view的应用到源码解读
对于从事大数据开发的同学,经常会应用到explode(炸裂函数)和lateral view(侧输出流). Explode(炸裂函数) 参数必须是array或者map格式(通常跟split函数使用): ...
- ios html zfplayer,【iOS】ZFPlayer源码解读中
前言 本篇继ZFPlayer源码解读基础之上,主要解析说明控制层与播放器,因为在上篇文章至现在并未提及丝毫关于这两个类业务的实现. 首先说下这两个类各自的职责. 控制层:主要负责响应与用户之间的交互, ...
- Java并发编程之ThreadLocal源码分析
1 一句话概括ThreadLocal 什么是ThreadLocal?顾名思义:线程本地变量,它为每个使用该对象的线程创建了一个独立的变量副本. 2 ThreadLocal使用场景 用一句话总结 ...
最新文章
- Gin源码解析和例子——路由
- 局域网伪造源地址DDoS***解决方法
- java的log4j的xml配置_Log4j配置实例(log4j.xml)
- 八十七、探究最短路问题:Dijkstra算法
- Select 可编辑 - 完美支持各大主流浏览器
- 优启通怎么重装系统win10_重装系统失败?小编教你安全给神舟战神GX9 Pro重装win10系统方法...
- 织梦dede企业律师事务所网模板源码
- Unity3d官方测试插件学习-单元测试,集成测试
- NLP最新趋势,7个主流业务场景!
- halcon学习之边缘检测
- 抖音python上的代码_抖音代码舞python实例代码
- matlab 冒泡排序函数,MATLAB实现冒泡排序算法
- 获取钉钉考勤机的打卡记录并且解析
- 重学 statistics, Cha10 Inference About Means and Proportions with Two Populations
- 互联网日报 | 6月8日 星期二 | 华为30亿成立数字能源公司;阿里明星直播业务“天猫星选”上线;苹果WWDC 2021开幕...
- 绝不要用的 Linux 命令 !
- PC端浏览器定位(纯前端)
- JAVAEE和项目开发——JSP详解
- Android的Activity之生命周期
- 【kaggle】特征工程 trick
热门文章
- hbase的shell客户端中不同符号的含义
- 神经网络中,正则化L1与L2的区别、如何选择以及代码验证
- 测试人员如何使用浏览器的f12_测试过程中如何快速定位一个bug
- 线上服务器登记的要点
- PLSQL Developer 运用Profiler 分析存储过程性能
- SQL Server 数据库关键知识点详解(优秀经典)
- linux下的struct sigaction
- SecureCRT登陆Centos 6.4乱码问题
- 【windows8开发】C++开发WinRT组件和JS调用
- NetBeans 时事通讯(刊号 # 134 - Jan 25, 2011)