详解一个ThreadLocal 的谜题
多线程如果不理解透彻, 那么 ThreadLocal 始终是有些会有所迷糊的。
ThreadLocal 本身的命名有有问题, 这些美国精英整出来的技术,再加上一个奇怪的命名。对我们中国人来说,就是一场场的灾难。
如下的问题, 你觉得输出是多少呢?
/*** Created by lk on 2017/6/8.*/ public class ThreadLocalTest extends Thread {ThreadLocal<Long> threadLocal = new ThreadLocal<Long>() {@Overrideprotected Long initialValue() {return 2L;}};public ThreadLocalTest() {setThreadLocal(new ThreadLocal<Long>());}@Overridepublic void run() {show();}public void setThreadLocal(ThreadLocal<Long> threadLocal) {this.threadLocal = threadLocal;threadLocal.set(10L);}public void show() {System.out.println( threadLocal.get());}public static void main(String[] args) {ThreadLocalTest ThreadLocalTest = new ThreadLocalTest();ThreadLocalTest.run();ThreadLocalTest.start();} }
答案是
10
null
这里有几个陷阱。
首先,ThreadLocalTest.run(); 这行由于要启动一个新的线程 以及它要初始化一个map(ThreadLocal 内部的东西)等, 它执行show 方法的时间通常会ThreadLocalTest.start(); 所以其实是 ThreadLocalTest.run(); 打印了null, 而 ThreadLocalTest.start(); 输出了 10。 就是说 后者比前者先输出。我们 把show 方法改成下面的样子:
System.out.println(" local = " + Thread.currentThread().getName() + " " + threadLocal.get());就会得到:
local = main 10
local = Thread-0 null
其次,ThreadLocalTest.run(); 和 ThreadLocalTest.start(); 方法看起来是执行了一样的代码, 其实不然, 这就是ThreadLocal 的非常的令人迷惑的地方。 要理解ThreadLocal , 关键在于理解其 get / set 方法, ThreadLocal 和 Thread 的关系, ThreadLocal 和 ThreadLocalMap 的关系 。一定要理清。 我们可以知道。 这里有两个线程, 一个是 main, 一个是 ThreadLocalTest。
main 线程的执行路径是: new 一个 ThreadLocalTest ,new 的过程中, 修改了当前类变量 threadLocal(其初始值是2L),让其指向了一个新的 ThreadLocal , 其没有初始值,也就是 null (查看源码可知)。 然后又将 其值设置为 10L。 这里一定要搞清楚, 最开始的那个 threadLocal 变量的堆实例已经无法获取了, 已经变成垃圾了, 随时可能被GC了, 现在的threadLocal 变量仅仅是一个 引用, 其指向的实例 已经不是原来那个了, 初始值已经变成了 null了。threadLocal.set(10L); 改成 this.threadLocal.set(10L); 是没有任何影响的, 他们是同一个实例。
至此, 我们应该明白了, main线程对应的 ThreadLocalMap 实例存放的 threadLocal 对应的 key 的 值 是 10L, 故 main 的start 方法调用的 show , get 到的 threadLocal 的值 就是 10。
ThreadLocalTest 线程的执行路径 是明显不同的, ThreadLocalTest 只管启动一个线程, 然后执行 run 方法,run 方法调用的 show , get 到的 threadLocal 的值 是多少呢? 我们先看一下 get 的源码比较好:
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();}
ThreadLocalTest 线程执行到 ThreadLocalMap map = getMap(t); 获取的 map 一定是 null, 因为ThreadLocalTest 线程 是刚刚创建的,其 对应的 ThreadLocalMap 一定是 null ( 查看 Thread 的源码可知), 这样, ThreadLocalMap 立即执行 return setInitialValue(); 尝试设置 初始值,然后返回初始值。 setInitialValue 方法 其实主要是获取了 initialValue 方法的值, 然后设置到了 ThreadLocalMap 中去。 前面的分析我们得知,现在的 threadLocal 已经被悄悄改变了, 它没有复写initialValue 方法, 其初始值就是默认值, 就是null。 故 get 的结果 就是 null 。 至此, 分析完毕。
欢迎热爱底层技术的人和我一起遨游技术的海洋。还有不懂的请留言。
转载于:https://www.cnblogs.com/FlyAway2013/p/7446394.html
详解一个ThreadLocal 的谜题相关推荐
- 交换机最多可以接几个_【技术】详解一个交换机能带动多少个网络监控摄像头?...
原标题:[技术]详解一个交换机能带动多少个网络监控摄像头? 一个交换机能带动多少个网络监控摄像头?千兆交换机一般接200万网络摄像机能接几个?24个网络头,用一台24口百兆交换机行不行?下面就这类问题 ...
- 详解一个Python库,用于构建精美数据可视化web app,练习做个垃圾分类app
点击上方"Python爬虫与数据挖掘",进行关注 回复"书籍"即可获赠Python从入门到进阶共10本电子书 今 日 鸡 汤 醉卧沙场君莫笑,古来征战几人回? ...
- 百度搜索研究,详解一个页面的索引价值!
写博客有一段时间,虽然每天的时间真的很忙,但我仍然保持着阅读的习惯,很多SEO小伙伴,习惯性的去找SEO干货,但有一些针对百度搜索的旧文档,我认为在今天,仍然给予我们很高的学习价值. 特别是当我建立S ...
- 循环嵌套思路详解 | 一个“在盒子里过家家”的算法 -- 以冒泡排序与打印菱形为例
目录 前言 一.引例 -- 菱形打印 1. 题干要求 2. 如何阅读循环结构? 二."在盒子里过家家"的理解思路 1. 什么叫"在盒子里过家家"? 一个小例子 ...
- Linux串口编程最全详解-一个努力奋斗的少年
NAME termios, tcgetattr, tcsetattr, tcsendbreak, tcdrain, tcflush, tcflow, cfmakeraw, cfgetospeed, c ...
- mysql scope runtime_Maven依赖scope属性详解-一个报错引发的问题 - 老郭种树
ApplicationEventMulticaster not initialized - call 'refresh' before multicasting events via the cont ...
- 【转】[SharePoint 开发详解] 一个Feature中使用SPGridView的几个Tips
根据上面一篇随笔所介绍的PC购买流程的项目,在项目中,需要有一个生成订单的功能,能够使得Admin很方便的在获得批准的申请中选取一些来生成订单,要求界面操作简单明了,大概的效果图如下: 点击check ...
- 详解一个自己原创的正则匹配IP的表达式
第一种方法(可以匹配有点毛病):检测IP地址的正则表达式 正则表达式: ((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d? ...
- 82、详解一个交换机能带动多少个网络监控摄像头
一个交换机能带动多少个网络监控摄像头?千兆交换机一般接200万网络摄像机能接几个?24个网络头,用一台24口百兆交换机行不行?下面就这类问题做一些简单的分析! 一.根据摄像机的码流和数量来选择 1.摄 ...
最新文章
- ViT(vision transformer)原理快速入门
- python的优点-Python语言的优势有哪些?
- 【BZOJ3242】【UOJ#126】【NOI2013】快餐店
- 【Java】6.3 类成员
- uabntu18.04 安装mysql5.7
- 2 中ascii函数_C语言编程预备知识--字节、ASCII
- 20幅扎心漫画,道尽无数人的人生!30万网友:这简直是在偷窥我生活...
- 信号与系统 chapter9 关于信号与系统中微分方程的求解
- mybatis oracle生成注释,MyBatis Generator生成Oracle数据库对应实体类时无法获取注释问题...
- 邮票面值设计java_邮票面值设计
- kubernetes kubeadm init this version of kubeadm only supports deploying clusters kubeadm版本降级
- 谷歌浏览器访问端口限制
- tensorflow目标检测API实现血细胞图像识别和计数
- pythonmd5解密代码_python写一个md5解密器示例,pythonmd5解密器
- HTML+CSS实战(哈罗单车首页)
- Linux应用程序开发 基础知识
- (转)EditText属性详解
- 卷积层TSNE可视化
- golang无穷大的判断
- 智能家居主要实现了什么功能,提供了哪些基本服务?
热门文章
- 纠错编码基本实验matlab,纠错编码基本实验matlab实现包含源代码
- java char 指针数组_双指针之对撞指针,Java
- matlab labs,DOCOMO Beijing Labs 借助 MATLAB 将移动通信技术的开发时间缩短 50%
- linux hrtimer 绑定cpu,Linux hrtimer分析--未配置高精度模式
- 从php到python的第一天
- python【蓝桥杯vip练习题库】ADV-233 队列操作
- 【Deep Learning笔记】神经网络的优化解读(看不懂你来打我~!)
- python【力扣LeetCode算法题库】15- 三数之和
- 【Network Security!】用户组管理与批处理中(:goto)的用法
- python123动物重量排序_python基本常识