详解一个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 。 至此, 分析完毕。

欢迎热爱底层技术的人和我一起遨游技术的海洋。还有不懂的请留言。

  

posted on 2017-08-29 00:30 CanntBelieve 阅读(...) 评论(...) 编辑 收藏

转载于:https://www.cnblogs.com/FlyAway2013/p/7446394.html

详解一个ThreadLocal 的谜题相关推荐

  1. 交换机最多可以接几个_【技术】详解一个交换机能带动多少个网络监控摄像头?...

    原标题:[技术]详解一个交换机能带动多少个网络监控摄像头? 一个交换机能带动多少个网络监控摄像头?千兆交换机一般接200万网络摄像机能接几个?24个网络头,用一台24口百兆交换机行不行?下面就这类问题 ...

  2. 详解一个Python库,用于构建精美数据可视化web app,练习做个垃圾分类app

    点击上方"Python爬虫与数据挖掘",进行关注 回复"书籍"即可获赠Python从入门到进阶共10本电子书 今 日 鸡 汤 醉卧沙场君莫笑,古来征战几人回? ...

  3. 百度搜索研究,详解一个页面的索引价值!

    写博客有一段时间,虽然每天的时间真的很忙,但我仍然保持着阅读的习惯,很多SEO小伙伴,习惯性的去找SEO干货,但有一些针对百度搜索的旧文档,我认为在今天,仍然给予我们很高的学习价值. 特别是当我建立S ...

  4. 循环嵌套思路详解 | 一个“在盒子里过家家”的算法 -- 以冒泡排序与打印菱形为例

    目录 前言 一.引例 -- 菱形打印 1. 题干要求 2. 如何阅读循环结构? 二."在盒子里过家家"的理解思路 1. 什么叫"在盒子里过家家"? 一个小例子 ...

  5. Linux串口编程最全详解-一个努力奋斗的少年

    NAME termios, tcgetattr, tcsetattr, tcsendbreak, tcdrain, tcflush, tcflow, cfmakeraw, cfgetospeed, c ...

  6. mysql scope runtime_Maven依赖scope属性详解-一个报错引发的问题 - 老郭种树

    ApplicationEventMulticaster not initialized - call 'refresh' before multicasting events via the cont ...

  7. 【转】[SharePoint 开发详解] 一个Feature中使用SPGridView的几个Tips

    根据上面一篇随笔所介绍的PC购买流程的项目,在项目中,需要有一个生成订单的功能,能够使得Admin很方便的在获得批准的申请中选取一些来生成订单,要求界面操作简单明了,大概的效果图如下: 点击check ...

  8. 详解一个自己原创的正则匹配IP的表达式

    第一种方法(可以匹配有点毛病):检测IP地址的正则表达式 正则表达式: ((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d? ...

  9. 82、详解一个交换机能带动多少个网络监控摄像头

    一个交换机能带动多少个网络监控摄像头?千兆交换机一般接200万网络摄像机能接几个?24个网络头,用一台24口百兆交换机行不行?下面就这类问题做一些简单的分析! 一.根据摄像机的码流和数量来选择 1.摄 ...

最新文章

  1. ViT(vision transformer)原理快速入门
  2. python的优点-Python语言的优势有哪些?
  3. 【BZOJ3242】【UOJ#126】【NOI2013】快餐店
  4. 【Java】6.3 类成员
  5. uabntu18.04 安装mysql5.7
  6. 2 中ascii函数_C语言编程预备知识--字节、ASCII
  7. 20幅扎心漫画,道尽无数人的人生!30万网友:这简直是在偷窥我生活...
  8. 信号与系统 chapter9 关于信号与系统中微分方程的求解
  9. mybatis oracle生成注释,MyBatis Generator生成Oracle数据库对应实体类时无法获取注释问题...
  10. 邮票面值设计java_邮票面值设计
  11. kubernetes kubeadm init this version of kubeadm only supports deploying clusters kubeadm版本降级
  12. 谷歌浏览器访问端口限制
  13. tensorflow目标检测API实现血细胞图像识别和计数
  14. pythonmd5解密代码_python写一个md5解密器示例,pythonmd5解密器
  15. HTML+CSS实战(哈罗单车首页)
  16. Linux应用程序开发 基础知识
  17. (转)EditText属性详解
  18. 卷积层TSNE可视化
  19. golang无穷大的判断
  20. 智能家居主要实现了什么功能,提供了哪些基本服务?

热门文章

  1. 纠错编码基本实验matlab,纠错编码基本实验matlab实现包含源代码
  2. java char 指针数组_双指针之对撞指针,Java
  3. matlab labs,DOCOMO Beijing Labs 借助 MATLAB 将移动通信技术的开发时间缩短 50%
  4. linux hrtimer 绑定cpu,Linux hrtimer分析--未配置高精度模式
  5. 从php到python的第一天
  6. python【蓝桥杯vip练习题库】ADV-233 队列操作
  7. 【Deep Learning笔记】神经网络的优化解读(看不懂你来打我~!)
  8. python【力扣LeetCode算法题库】15- 三数之和
  9. 【Network Security!】用户组管理与批处理中(:goto)的用法
  10. python123动物重量排序_python基本常识