ThreadLocal 是一个老生常谈的问题,在源码学习以及实际项目研发中,往往都能见到它的踪影,用途比较广泛,所以有必要深入一番。

敢问,ThreadLocal 都用到了哪里?有没有运用它去解决过业务问题呢?

没用过、答不上来也没关系,因为通过今天的分享,能让你轻松 get 如下几点,收获满满。

a)ThreadLocal 快速入门;

b)ThreadLocal 源码解读;

c)ThreadLocal 使用场景;

d)ThreadLocal 阿里规约中的奇技淫巧。

1. ThreadLocal 快速入门

理论暂且不谈,ThreadLocal 到底该怎么用?don't talk, show me the code!

上图是老项目真实在用的一个场景,主要借助 ThreadLocal 统计请求处理的耗时。仔细去看 ThreadLocal 使用起来其实蛮简单,接下来通过一段代码,让你快速掌握 ThreadLocal 的使用。

如上面代码所示,模拟一个业务请求处理耗时的场景,我们跑起来,看一看。

虽然代码能跑起来,充其量只是带你熟练使用了一把 ThreadLocal 的 API,并没有充分体会到 ThreadLocal 的核心设计理念。

看官别急,容我稍微修饰修饰代码,请看仔细。

代码调整很简单,就是把 main 方法中的代码,挪到线程体内去执行,然后看看获取请求开始时设置的时间值,是否会在多线程情况下而发生错乱?代码不会骗人的,跑起来看一看。

依据程序结果,就可以简单对 ThreadLocal 做个小结。

第一:对于 ThreadLocal 而言,最常用的 API,就是 get、set、remove,其实还有 initialValue(常用来在创建 ThreadLocal 对象时设置初始值);

第二:针对程序输出的结果而言,站在线程的角度去看,就好像每一个线程都完全拥有 ThreadLocal 的变量,感觉就是为每一个使用该变量的线程都提供一个变量值的副本,使每一个线程都可以独立的改变自己的副本,而不会和其它线程的副本发生冲突。

第三:坊间说 ThreadLocal 是 Thread Local Variable(线程局部变量)的意思,或许将它命名为 ThreadLocalVar 会更加合适。

总结起来就一句「通过 ThreadLocal 能达到线程隔离的机制」,这句话真的对吗?其实是要持怀疑态度的。

don’t talk, show me the code!代码不会骗人的,拿出证据来。

上面代码是假想的一个场景,主要看代码。按照 ThreadLocal 的设计理念,会直接断言每个线程的序列号独立维护,互不影响。

可是结果却差点意思,居然没有达到线程隔离的效果,程序真实输出如下。

现象:当 ThreadLocal 设置的 value 都指向同一个对象(示例中的 FlowNo 对象),这个时候 ThreadLocal 就失灵啦(其实是有点难理解,没关系,后面有图解释)。

烟未灭,酒过半,是时候走进 JDK 源码看一看。

2. ThreadLocal 源码解读

首先从常用的 set 方法作为切入点,若搞懂这个方法,把 ThreadLocal 差不多就看穿啦。

如红色圈住部分代码,简单释义。

a)首先获取当前线程的对象 t;

b)然后获取 t 对应的成员变量 ThreadLocalMap;

c)接着判断 ThreadLocalMap 是否为空,不为空则将 ThreadLocal 和新的 value 放入到 ThreadLocalMap 中;

d)如果 ThreadLocalMap 为空,则对线程的成员变量 ThreadLocalMap 进行初始化操作,并将 ThreadLocal 和 value 放入 ThreadLocalMap 中。

哎呦,我去!ThreadLocal 刚用明白,这 ThreadLocalMap 又是什么鬼?别急,我们慢慢细看。

通过上面源码,可以清楚的知道 ThreadLocalMap 是 ThreadLocal 中的一个静态内部类,而 ThreadLocalMap 里面定义了一个静态的内部类 Entry 来保存数据,在 Entry 内部使用 ThreadLocal 作为 key,而 value 就是要设置的值(WeakReference,稍微留意一下,后面会再次提及)。

说了这么多,感觉苦涩的文字,不如粗糙的图一张(想着点开篇的代码,说不定就醍醐灌顶啦,记住这个图就行啦)。

还记得开篇案例最后一个现象吗?当 ThreadLocal 设置的 value 都指向同一个对象,ThreadLocal 就失灵啦。

依据上图,如果设置的 value 初始值均都指向同一个对象时(指的是Entry的value),多线程情况下,不发生影响才怪。

另外,对照着上面的图,再去看 get 方法,就相对好理解很多啦,不再贴代码,直接去看 remove 方法的源码。

remove 方法很简单,主要把 ThreadLocal 对象做为 key 从 ThreadLocalMap 清除对应的 Entry。

remove 方法的用途在哪里?结合下面下面这个继承关系图去说说。

依据上图所示,很明显 Entry 的 Key 是一个 WeakReference 弱引用(ThreadLocal 使用到了弱引用),极端情况下可能会发生内存泄露,所以代码上最终建议调用 remove 方法释放内存,避免发生内存泄露。

本次源码剖析就到这里,接下来我们看看 ThreadLocal 的主要使用场景。

3. ThreadLocal 使用场景

ThreadLocal 使用场景其实非常多,下面简单列举几个。

a) Java 日志门面 org.sl4j.MDC 底层使用 ThreadLocal 来保证线程之间的数据隔离及数据传递;

b) Hiberante 的Session工具类 HibernateUtil,借用 ThreadLocal 用于 session 管理(老项目还在用);

c)分布式链路跟踪;

d)类似项目研发中统计方法耗时,记录登录 Session 信息,用户 ID 等等;

e) JDK 7 之后提供的随机数生成器 ThreadLocalRandom,底层也借用 ThreadLocal 来实现。

4. ThreadLocal 阿里规约中的奇技淫巧

【强制】必须回收自定义的 ThreadLocal 变量,尤其在线程池场景下,线程经常会被复用, 如果不清理自定义的 ThreadLocal 变量,可能会影响后续业务逻辑和造成内存泄露等问题。尽量在代理中使用 try-finally 块进行回收。

正例:
objectThreadLocal.set(userInfo);
try {
// ...
} finally {
objectThreadLocal.remove();
}

【参考】ThreadLocal 对象使用 static 修饰,ThreadLocal 无法解决共享对象的更新问题。

说明:这个变量是针对一个线程内所有操作共享的,所以设置为静态变量,所有此类实例共享此静态变量,也就是说在类第一次被使用时装载,只分配一块存储空间,所有此类的对象(只要是这个线程内定义的)都可以操控这个变量。

阿里开发规约对于 ThreadLocal 推荐使用约定,势必对你会有一定的参考价值。另外,继华山版之后泰山版的开发规约已经新鲜出炉啦,大家可以自行下载。

5. 写在最后

行文至此,接近尾声,本次主要带你对 ThreadLocal 进行快速入门,并通过剖析源码,带你知晓 ThreadLocal 背后的东西,最后对阿里开发规约中 ThreadLocal 的使用约定简单罗列,相信会对你实践有一定的指导意义。

本次分享就到这里,希望对你有所帮助吧。

一起聊技术、谈业务、喷架构,少走弯路,不踩大坑。会持续输出原创精彩分享,敬请期待!

ThreadLocal 是什么鬼?用法、源码一锅端的更多相关文章

  1. 并发编程学习笔记(8)----ThreadLocal的使用及源码分析

    1. ThreadLocal的理解 ThreadLocal,顾名思义,就是线程的本地变量,ThreadLocal会为每个线程创建一个本地变量副本,使得使用ThreadLocal管理的变量在多线程的环境 ...

  2. MDC是什么鬼?用法、源码一锅端

    近期用到阿里的一款开源的数据同步工具 Canal,不经意之中看到了 MDC 的用法,而且平时项目中也多次用到 MDC,趁机科普一把. 通过今天的分享,能让你轻松 get 如下几点,绝对收获满满. a) ...

  3. 【Java并发编程】面试常考的ThreadLocal,超详细源码学习

    目录 ThreadLocal是啥?用来干啥? ThreadLocal的简单使用 ThreadLocal的实现思路? ThreadLocal常见方法源码分析 ThreadLocal.set(T valu ...

  4. 结合ThreadLocal来看spring事务源码,感受下清泉般的洗涤!

    在我的博客spring事务源码解析中,提到了一个很关键的点:将connection绑定到当前线程来保证这个线程中的数据库操作用的是同一个connection.但是没有细致的讲到如何绑定,以及为什么这么 ...

  5. ThreadLocal的原理,源码深度分析及使用

    文章简介 ThreadLocal应该都比较熟悉,这篇文章会基于ThreadLocal的应用以及实现原理做一个全面的分析 内容导航 什么是ThreadLocal ThreadLocal的使用 分析Thr ...

  6. 类ThreadLocal的使用与源码分析

    变量值的共享可以使用public static的形式,所有的线程都使用同一个变量.如果每个线程都有自己的共享变量,就可以使用ThreadLocal.比如Hibernat的session问题就是存在Th ...

  7. Android多线程全面解析:IntentService用法&源码

    前言 多线程的应用在Android开发中是非常常见的,常用方法主要有: 继承Thread类 实现Runnable接口 AsyncTask Handler HandlerThread IntentSer ...

  8. ThreadLocal应用场景以及源码分析

    一.应用篇 ThreadLocal介绍 ThreadLocal如果单纯从字面上理解的话好像是“本地线程”的意思,其实并不是这个意思,只是这个名字起的太容易让人误解了,它的真正的意思是线程本地变量. 实 ...

  9. Java ThreadLocal 的使用与源码解析

    GitHub Page: http://blog.cloudli.top/posts/Java-ThreadLocal-的使用与源码解析/ ThreadLocal 主要解决的是每个线程绑定自己的值,可 ...

随机推荐

  1. 对于一个由0..n的所有数按升序组成的序列,我们要进行一些筛选,每次我们取当前所有数字中从小到大的第奇数位个的数,并将其丢弃。重复这一过程直到最后剩下一个数。请求出最后剩下的数字。

    输入描述: 每组数据一行一个数字,为题目中的n(n小于等于1000). 输出描述: 一行输出最后剩下的数字.我的思路是用两个链表,一个用于存储原数据,一个用于存储要丢掉的数据,再循环从元数据中剔除掉即 ...

  2. WeChat-SmallProgram:自定义select下拉选项框组件

    1):创建组件所需的文件 2):自定义组件 CSS 及 JS 组件的wxml: <view class='com-selectBox'> <view class='com-sCont ...

  3. C 最大公约数&最小公倍数

    1.最大公约数  链接 如果有一个自然数a能被自然数b整除,则称a为b的倍数,b为a的约数.几个自然数公有的约数,叫做这几个自然数的公约数.公约数中最大的一个公约数,称为这几个自然数的最大公约数. 1 ...

  4. ios shell打包脚本 xctool

    #! /bin/bash project_path=$() project_config=Release output_path=~/Desktop build_scheme=YKTicketsApp ...

  5. CVE-2020-7961 Liferay Portal 复现分析

    漏洞说明: Liferay是一个开源的Portal(认证)产品,提供对多个独立系统的内容集成,为企业信息.流程等的整合提供了一套完整的解决方案,和其他商业产品相比,Liferay有着很多优良的特性,而 ...

  6. Spring Boot 整合视图层技术,application全局配置文件

    目录 Spring Boot 整合视图层技术 Spring Boot 整合jsp Spring Boot 整合freemarker Spring Boot 整合视图层技术 Spring Boot 整合 ...

  7. php设计模式总结

    #1 使用设计模式(如建造者.外观.原型和模板模式)更快速.更有效地创建对象 #2 使用数据访问对象和代理设计模式分离体系结构 #3 使用委托.工厂和单元素设计模式改善代码流和控制 #4 在不修改对象 ...

  8. 从零搭建一个SpringCloud项目之Zuul(四)

    整合Zuul 为什么要使用Zuul? 易于监控 易于认证 减少客户端与各个微服务之间的交互次数 引入依赖 <dependency> <groupId>org.springfra ...

  9. Docker的简介以及Dockerfile编写与使用

    Docker的简介 Docker是在容器的基础上,进行了进一步的封装,极大的简化了容器的创建和维护.使得Docker技术比虚拟机技术更为轻便.快捷. 下面是两张对比图. 可以看到传统虚拟机技术是虚拟出 ...

  10. Flutter 实现网易云音乐字幕

    老孟导读:没有接触过音乐字幕方面知识的话,会对字幕的实现比较迷茫,什么时候转到下一句?看了这篇文章,你就会明白字幕so easy. 先来一张效果图: 字幕格式 目前市面上有很多种字幕格式,比如srt, ...