今天听到一个老哥说道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. c#如何使用replace函数将"\"替换成"\\"

    当我使用 String str="c:\aa.xls"; str=str.Replace("\","\\");时,括号为红色错误的,那么如何 ...

  2. 1268 和为K的组合 Meet in mid二分思路

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1268&judgeId=193772 给出n = 20个数,问其是 ...

  3. SQL常用系统信息语句

    一.查询指定表外键约束 SELECT  A.name AS 约束名 ,        OBJECT_NAME(B.parent_object_id) AS 外键表 ,        D.name AS ...

  4. 2017广东工业大学程序设计竞赛决赛 G 等凹数字

    题意: Description 定义一种数字称为等凹数字,即从高位到地位,每一位的数字先非递增再非递减,不能全部数字一样,且该数是一个回文数,即从左读到右与从右读到左是一样的,仅形成一个等凹峰,如54 ...

  5. ES6语法糖集锦

    sublime3安装Es6插件 javascriptNext,然后安装即可 Java​Script​Next - ES6 Syntax()高亮插件 -------------------------- ...

  6. q-oo-p , a piggy domain name. Very cute. boyan.zheng at foxmail.com

    Contact me.

  7. 使用 reduce 实现数组 map 方法

    //使用 reduce 实现数组 map 方法 const selfMap2 = function (fn, context){ let arr = Array.prototype.slice.cal ...

  8. 前端工程化与webpack

    (1) 前端工程化   近几年来,前端领域飞速发展,前端的工作早已不再是切几张图,写几个页面那么简单,项目比较大时,很可能会多人协同开发,模块化,组件化,CSS预编译等技术也被广泛的使用.前端自动化( ...

  9. java解决动态的锁顺序死锁的方案

    直接上代码 public class Test3 { public static Object fromAccount = new String("1"); public stat ...

  10. ubuntu12.04 配置apache+modwsgi+django1.5

    1.首先下载modwsgi  链接如下: http://files.cnblogs.com/baoyiluo/mod_wsgi-3.4.zip 2.解压并安装mod_wsgi: ./configure ...