今天听到一个老哥说道ThreadLocal在源码设计上面的一些好处,于是决定把ThreadLocal源码彻底分析一下。

首先,我们来看下set方法

可以看到,这个方法里,先获得了当前线程,之后将当前线程传入了一个方法

此处返回了当前线程的一个成员变量

此时我们第一次调用,肯定为空,那么我们进入为空的判断看下方法

可以看到,new了一个ThreadLocalMap并将当前的ThreadLocal对象作为键,我们要存入的值作为值传入

来看下这个ThreadLocalMap到底为何物吧。

这就是它的庐山真面目,一个ThreadLocal里的内部类,我们看下它的构造方法

创建了一个16长度的Entry数组

之后做了一个二进制与运算,拿到一个整型,并将我们传入的this和值当做参数传入了一个Entry对象并赋值给了数组,请记住这里面做位运算的数是使用了AutomicInteger做++操作的,因为ThreadLocal可以被多个线程转换为索引的

这就是最后的操作,将我们的当前ThreadLocal对象变成了一个弱引用,方便回收,并将我们传入的值赋值给了其内部的变量value.

再来看下我们的get()方法

可以看到,先拿到了我们当前线程,并通过当前线程拿到了当前的ThreadLocalMap,这里不再截图,可以看上面set()方法的讲解

如果map不为空的话就会将我们的this传入getEntity方法()

可以看到,依然是做了与二进制运算拿到保存在Entry数组里对应的Entry.

再次回到此图,可以看到直接返回了我们保存在Entry中value变量的值。

而如果Map为空呢?

点进initialValue()方法

返回了一个Null.

并且因为接下来如果当前线程的ThreadLocalMap不为空则将当前ThreadLocal与null值传入。

如果为空则创建一个。

总结:ThreadLocal实现了多线程间能根据线程来保存值的原因在于它会拿到当前线程里的一个属性,ThreadLocalMap,并且因为是线程里的属性,所以当然是线程安全的。之后创建一个数组,并将创建一个将我们ThreadLocal以及我们要存入的值作为参数传入的Entry对象,并存入数组。而在Entry对象内部则是将我们的this变成了一个弱引用,并将我们的值赋值给了它内部的一个成员变量。

而当我们想要拿到的时候,它则是从当前线程拿到对应的ThreadLocalMap,并通过map将this传入拿到当前线程对应的Entry,之后直接从Entry中取到值

此处可能有点难以理解,但只要记住,我们的ThreadLocal是唯一的,但我们的ThreadLocalMap()是每个线程都不同的,它是线程的一个属性。我们存入的时候,是根据这个ThreadLocal获得索引存入table数组中的。所以我们才能通过固定的ThreadLocal再次拿到索引,从而在不同的map里拿到对应Entry,达到线程隔离的效果。

2018/3/3 解析ThreadLocal源码的更多相关文章

  1. 并发编程(四)—— ThreadLocal源码分析及内存泄露预防

    今天我们一起探讨下ThreadLocal的实现原理和源码分析.首先,本文先谈一下对ThreadLocal的理解,然后根据ThreadLocal类的源码分析了其实现原理和使用需要注意的地方,最后给出了两 ...

  2. 并发-ThreadLocal源码分析

    ThreadLocal源码分析 参考: http://www.cnblogs.com/dolphin0520/p/3920407.html https://www.cnblogs.com/coshah ...

  3. 硬核剖析ThreadLocal源码,面试官看了直呼内行

    工作面试中经常遇到ThreadLocal,但是很多同学并不了解ThreadLocal实现原理,到底为什么会发生内存泄漏也是一知半解?今天一灯带你深入剖析ThreadLocal源码,总结ThreadLo ...

  4. Java多线程9:ThreadLocal源码剖析

    ThreadLocal源码剖析 ThreadLocal其实比较简单,因为类里就三个public方法:set(T value).get().remove().先剖析源码清楚地知道ThreadLocal是 ...

  5. Python解析器源码加密系列之(二):一次使用标准c的FILE*访问内存块的尝试

    摘要:由于近期打算修改Python解释器以实现pyc文件的加密/解密,出于保密的要求,解密之后的数据只能放在内存中,不能写入到文件中.但是后续的解析pyc文件的代码又只能接受FILE*作为入参,所以就 ...

  6. HtmlAgilityPack --解析Html源码

    最近项目需要从网络上抓取一下数据解析Html源码,奈何正则表达式难写,于是网上搜索找到了“ HtmlAgilityPack”类库,敏捷开发,果然效率非同寻常. 在此做笔记,写下心得,顺便给自己总结一下 ...

  7. mvc5 解析route源码实现自己的route系统

    Asp.net mvc5 解析route源码实现自己的route系统   url route 路由系统的责任是找到匹配的路由,创建路由数据,并将请求分配给一个处理程序. 选择动作是 MVC 的处理程序 ...

  8. 浩哥解析MyBatis源码(十)——Type类型模块之类型处理器

    原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6715063.html 1.回顾 之前的两篇分别解析了类型别名注册器和类型处理器注册器,此二 ...

  9. Java多线程学习之ThreadLocal源码分析

    0.概述 ThreadLocal,即线程本地变量,是一个以ThreadLocal对象为键.任意对象为值的存储结构.它可以将变量绑定到特定的线程上,使每个线程都拥有改变量的一个拷贝,各线程相同变量间互不 ...

随机推荐

  1. 203 Remove Linked List Elements 删除链表中的元素

    删除链表中等于给定值 val 的所有元素.示例给定: 1 --> 2 --> 6 --> 3 --> 4 --> 5 --> 6, val = 6返回: 1 --& ...

  2. hbase rpc这点事

    年前的时候系统梳理了一下hbase rpc的实现,并且对组里的小伙伴做了一次分享.趁着热乎劲还没完全消失殆尽,准备赶紧记录下来. hbase中rpc概况 作为一个分布式系统,hbase的设计是典型的m ...

  3. 一个页面通过iframe,获取另一个页面的form

    document.getElementsByTagName("iframe")[0].contentWindow.document.forms[0].submit(); var z ...

  4. AJPFX关于static总结

    static 总结 static Fields        static Methods        static member class        static initializer-- ...

  5. AJPFX实践 java实现快速排序算法

    快速排序算法使用的分治法策略来把一个序列分为两个子序列来实现排序的思路: 1.从数列中挑出一个元素,称为“基准“2.重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面 ...

  6. UnixTime的时间戳的转换

    public static string XConvertDateTime(double unixTime) { System.DateTime time = System.DateTime.MinV ...

  7. Android 使用EventBus进行Fragment和Activity通信

    本文介绍EventBus的基本使用,以及用于Fragment和Activity之间通信. github地址: https://github.com/greenrobot/EventBus 版本是 Ev ...

  8. java 之冒泡排序

    冒泡排序:可以想象成煮开水,气泡在瓶底的时候是比较小的,到达水面的时候达到最大. 冒泡排序的思想:先确定是升序还是降序,这里升序为例.每两个相邻的数字进行比较,前一个数字比后面一个数字大,就将两个数字 ...

  9. 数据分析师入门|Python安装MAC版

    最近在学数据分析师入门课,看了大纲,感觉终于不再慌乱踩坑了,开始存档最粗暴版学习笔记,遇到停止的地方按照下文红字直接输入就OK,方便和我一样的小伙伴参考呀,老师讲的很适合我这种初学者,PUSH了很多资 ...

  10. 删数问题(Noip1994)

    1321:[例6.3]删数问题(Noip1994) 时间限制: 1000 ms         内存限制: 65536 KB提交数: 5127     通过数: 1595 [题目描述] 输入一个高精度 ...