ThreadLocal原理详解——终于弄明白了ThreadLocal
目录
概述
在java学习生涯中可能很多人都会听到ThreadLocal变量,从字面上理解ThreadLocal就是“线程局部变量”的意思。简单的说就是,一个ThreadLocal在一个线程中是共享的,在不同线程之间又是隔离的(每个线程都只能看到自己线程的值)。可能一开始把这句话放出来很难理解,那我们就继续往后面看吧。
API介绍
再学习一个类之前我们需要了解一个类的API,这也是我们学习类的入口。而ThreadLocal类的API相当简单。

在这里面比较重要的就是,get、set、remove了,这三个方法是对这个变量进行操作的关键。set用于赋值操作,get用于获取变量中的值,remove就是删除当前这个变量的值。需要注意的是initialValue方法会在第一次调用时被触发,用于初始化当前变量值,例如在下列代码中我们需要创建一个ThreadLocal<Connection>,用于创建一个与线程绑定的Connection对象:
ThreadLocal<Connection> connection = new ThreadLocal<Connection>(){
public Connection initialValue(){
return DriverManager.getConnection(...);
}
};
为什么我们将ThreadLocal说成变量,我们姑且可以这么理解,每个ThreadLocal实例中都可以保存一个值(基本数据类型值或者引用类型的引用值),而内部保存的值是可以修改的,而这样的特性与变量的特性及其相似,变量不就是用来保存一个值的吗?
也就是说每一个ThreadLocal实例就类似于一个变量名,不同的ThreadLocal实例就是不同的变量名,它们内部会存有一个值(暂时这么理解)在后面的描述中所说的“ThreadLocal变量或者是线程变量”代表的就是ThreadLocal类的实例。
这里还需要介绍一下initialValue方法,我么都知道在Java中成员变量都会有默认值,而ThreadLocal做变量也会有默认值,那我们可以通过重写initialValue方法指定ThreadLocal变量的初始值。默认情况下initialValue返回的是null。
ThreadLocal的理解
说完了ThreadLocal类的API了,那我们就来动手实践一下了,来理解前面没有理解的那句话:一个ThreadLocal在一个线程中是共享的,在不同线程之间又是隔离的(每个线程都只能看到自己线程的值)
public class ThreadLocalTest {
private static ThreadLocal<Integer> num = new ThreadLocal<Integer>() {
// 重写这个方法,可以修改“线程变量”的初始值,默认是null
@Override
protected Integer initialValue() {
return 0;
}
};
public static void main(String[] args) {
// 创建一号线程
new Thread(new Runnable() {
@Override
public void run() {
// 在一号线程中将ThreadLocal变量设置为1
num.set(1);
System.out.println("一号线程中ThreadLocal变量中保存的值为:" + num.get());
}
}).start();
// 创建二号线程
new Thread(new Runnable() {
@Override
public void run() {
num.set(2);
System.out.println("二号线程中ThreadLocal变量中保存的值为:" + num.get());
}
}).start();
//为了让一二号线程执行完毕,让主线程睡500ms
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("主线程中ThreadLocal变量中保存的值:" + num.get());
}
}
稍微解释一下上面的代码:
在类中创建了一个静态的“ThreadLocal变量”,在主线程中创建两个线程,在这两个线程中分别设置ThreadLocal变量为1和2。然后等待一号和二号线程执行完毕后,在主线程中查看ThreadLocal变量的值。
程序结果及分析

程序结果重点看的是主线程输出的是0,如果是一个普通变量,在一号线程和二号线程中将普通变量设置为1和2,那么在一二号线程执行完毕后在打印这个变量,输出的值肯定是1或者2(到底输出哪一个由操作系统的线程调度逻辑有关)。但使用ThreadLocal变量通过两个线程赋值后,在主线程程中输出的却是初始值0。在这也就是为什么“一个ThreadLocal在一个线程中是共享的,在不同线程之间又是隔离的”,每个线程都只能看到自己线程的值,这也就是ThreadLocal的核心作用:实现线程范围的局部变量。
ThreadLocal的原理分析
老规矩我们还是将最后结论摆在前面,每个Thread对象都有一个ThreadLocalMap,当创建一个ThreadLocal的时候,就会将该ThreadLocal对象添加到该Map中,其中键就是ThreadLocal,值可以是任意类型。这句话看不懂很正常,等我们一起看完源码以后就明白了。
此时就需要纠正前面提到的错误观点了,前面我们的理解是所有的常量值或者是引用类型的引用都是保存在ThreadLocal实例中的,但实际上不是的,这种说法只是让我们更好的理解ThreadLocal变量这个概念。向ThreadLocal存入一个值,实际上是向当前线程对象中的ThreadLocalMap存入值,ThreadLocalMap我们可以简单的理解成一个Map,而向这个Map存值的key就是ThreadLocal实例本身。

也就是说,想要存入的ThreadLocal中的数据实际上并没有存到ThreadLocal对象中去,而是以这个ThreadLocal实例作为key存到了当前线程中的一个Map中去了,获取ThreadLocal的值时同样也是这个道理。这也就是为什么ThreadLocal可以实现线程之间隔离的原因了。
总结
ThreadLocal的作用:实现线程范围内的局部变量,即ThreadLocal在一个线程中是共享的,在不同线程之间是隔离的。
ThreadLocal的原理:ThreadLocal存入值时使用当前ThreadLocal实例作为key,存入当前线程对象中的Map中去。最开始在看源码之前,我以为是以当前线程对象作为key将对象存入到ThreadLocal中的Map中去....
各位大佬,原创不易呀,路过的点个赞!!!
ThreadLocal原理详解——终于弄明白了ThreadLocal的更多相关文章
- select用法&原理详解(源码剖析)(转)
今天遇到了在select()前后fd_set的变化问题,查了好久终于找到一个有用的帖子了,很赞,很详细!!原文链接如下: select用法&原理详解(源码剖析) 我的问题是: 如下图示:在se ...
- Nginx与PHP-FPM运行原理详解
目录 1. 代理与反向代理 1. 正向代理:访问google.com 2. 反向代理:通过反向代理实现负载均衡 2. 初识Nginx与PHP-FPM 1. Nginx是什么 2. CGI与FastCG ...
- Storm概念、原理详解及其应用(一)BaseStorm
本文借鉴官文,添加了一些解释和看法,其中有些理解,写的比较粗糙,有问题的地方希望大家指出.写这篇文章,是想把一些官文和资料中基础.重点拿出来,能总结出便于大家理解的话语.与大多数“wordcount” ...
- JSPatch实现原理详解<二>
本文转载至 http://blog.cnbang.net/tech/2855/ 距离上次写的<JSPatch实现原理详解>有一个月的时间,在这段时间里 JSPatch 在不断地完善和改进, ...
- 0614MySQL的InnoDB索引原理详解
转自http://www.cnblogs.com/shijingxiang/articles/4743324.html MySQL的InnoDB索引原理详解 http://www.admin10000 ...
- CentOS 6.5 iptables原理详解以及功能说明
CentOS 6.5 iptables原理详解以及功能说明 来源 https://blog.51cto.com/tanxw/1389114 前言 iptables其实就是Linux下的一个开源的信息过 ...
- sso单点登录原理详解
sso单点登录原理详解 01 单系统登录机制 1.http无状态协议 web应用采用browser/server架构,http作为通信协议.http是无状态协议,浏览器的每一次请求,服务 ...
- 通过 JFR 与日志深入探索 JVM - TLAB 原理详解
全系列目录:通过 JFR 与日志深入探索 JVM - 总览篇 什么是 TLAB? TLAB(Thread Local Allocation Buffer)线程本地分配缓存区,这是一个线程专用的内存分配 ...
- I2C 基础原理详解
今天来学习下I2C通信~ I2C(Inter-Intergrated Circuit)指的是 IC(Intergrated Circuit)之间的(Inter) 通信方式.如上图所以有很多的周边设备都 ...
- Zigbee组网原理详解
Zigbee组网原理详解 来源:互联网 作者:佚名2015年08月13日 15:57 [导读] 组建一个完整的zigbee网状网络包括两个步骤:网络初始化.节点加入网络.其中节点加入网络又包括两个 ...
随机推荐
- CentOS 6.5快速部署HTTP WEB服务器和FTP服务器
CentOS 6.5快速部署HTTP WEB服务器和FTP服务器 时间:2014-03-29 来源:服务器之家 投稿:root 点击:210次 [题记]本文使用CentOS 6.5m ...
- RestfulApi 学习笔记——父子资源(四)
前言 该系列前文提及到,要体现出资源的一个结构,那么如何体现出结构呢?比如说获取emproyee,应该写/api/companies/1/emproyees,这样可以体现其结构性. 那么这样改如何设置 ...
- 认识tensorflow - 【老鱼学tensorflow2】
深度学习是模仿了生物的神经元的概念,你可以想象用一大堆的神经元通过各种刺激来对外部世界进行感知,从而建立起对外部世界的模型. 比如给你一个数据对: x y -1 -3 0 -1 1 1 2 3 3 5 ...
- WAF网站访问限制
请参考:https://www.cnblogs.com/yangyangblog/p/14930159.html 文件下载的地方可以网络搜索,这里提供IIS7 WINDOWS64位版本:https:/ ...
- Java Map中那些巧妙的设计
简介: 他山之石可以攻玉,这些巧妙的设计思想非常有借鉴价值,可谓是最佳实践.然而,大多数有关Java Map原理的科普类文章都是专注于"点",并没有连成"线", ...
- 揭秘 cache 访问延迟背后的计算机原理
简介:本文介绍如何测试多级 cache 的访存延迟,以及背后蕴含的计算机原理. CPU 的 cache 往往是分多级的金字塔模型,L1 最靠近 CPU,访问延迟最小,但 cache 的容量也最小.本 ...
- 【实践案例】Databricks 数据洞察 Delta Lake 在基智科技(STEPONE)的应用实践
简介: 获取更详细的 Databricks 数据洞察相关信息,可至产品详情页查看:https://www.aliyun.com/product/bigdata/spark 作者 高爽,基智科技数据中心 ...
- Cloudera CDP 企业数据云测试开通指导
简介:基于阿里云部署的 Cloudera CDP 企业数据云平台已经进入公测阶段,本文详细介绍了相关试用/试用流程. 基于阿里云部署的 Cloudera CDP 企业数据云平台已经进入公测阶段,如对 ...
- 前沿分享|阿里云资深技术专家 魏闯先:AnalyticDB PostgreSQL年度新版本发布
简介: 本篇内容为2021云栖大会-云原生数据仓库AnalyticDB技术与实践峰会分论坛中,阿里云资深技术专家 魏闯先关于"AnalyticDB PostgreSQL年度新版本发布&qu ...
- [Blockchain] 开发完真实的 DApp 后才能得出的结论与看法
1. 最近经常看到地方新闻有关 区块链在追踪溯源方面被实际应用,但是我本人认为这很大程度上可能是伪命题. 因为,是不是区块链.或者说有没有办法更改数据,这都很难说,本质上这个链还是由机构控制,所以对此 ...