手撕面试题ThreadLocal!!!
说明
面试官:讲讲你对ThreadLocal的一些理解。
那么我们该怎么回答呢????你也可以思考下,下面看看零度的思考;
ThreadLocal用在什么地方?
ThreadLocal一些细节!
ThreadLocal的最佳实践!
思考
ThreadLocal用在什么地方?
讨论ThreadLocal用在什么地方前,我们先明确下,如果仅仅就一个线程,那么都不用谈ThreadLocal的,ThreadLocal是用在多线程的场景的!!!
ThreadLocal归纳下来就2类用途:
- 保存线程上下文信息,在任意需要的地方可以获取!!!
- 线程安全的,避免某些情况需要考虑线程安全必须同步带来的性能损失!!!
保存线程上下文信息,在任意需要的地方可以获取!!!
由于ThreadLocal的特性,同一线程在某地方进行设置,在随后的任意地方都可以获取到。从而可以用来保存线程上下文信息。
常用的比如每个请求怎么把一串后续关联起来,就可以用ThreadLocal进行set,在后续的任意需要记录日志的方法里面进行get获取到请求id,从而把整个请求串起来。
还有比如Spring的事务管理,用ThreadLocal存储Connection,从而各个DAO可以获取同一Connection,可以进行事务回滚,提交等操作。
备注: ThreadLocal的这种用处,很多时候是用在一些优秀的框架里面的,一般我们很少接触,反而下面的场景我们接触的更多一些!
线程安全的,避免某些情况需要考虑线程安全必须同步带来的性能损失!!!
ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。但是ThreadLocal也有局限性,我们来看看阿里规范:
每个线程往ThreadLocal中读写数据是线程隔离,互相之间不会影响的,所以ThreadLocal无法解决共享对象的更新问题!
由于不需要共享信息,自然就不存在竞争问题了,从而保证了某些情况下线程的安全,以及避免了某些情况需要考虑线程安全必须同步带来的性能损失!!!
这类场景阿里规范里面也提到了:
ThreadLocal一些细节!
ThreaLocal使用示例代码:
public class ThreadLocalTest {
private static ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
public static void main(String[] args) {
new Thread(() -> {
try {
for (int i = 0; i < 100; i++) {
threadLocal.set(i);
System.out.println(Thread.currentThread().getName() + "====" + threadLocal.get());
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} finally {
threadLocal.remove();
}
}, "threadLocal1").start();
new Thread(() -> {
try {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + "====" + threadLocal.get());
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} finally {
threadLocal.remove();
}
}, "threadLocal2").start();
}
}
代码截图:
代码运行结果:
从运行的结果我们可以看到threadLocal1进行set值对threadLocal2并没有任何影响!
Thread、ThreadLocalMap、ThreadLocal总览图
Thread类有属性变量threadLocals (类型是ThreadLocal.ThreadLocalMap),也就是说每个线程有一个自己的ThreadLocalMap ,所以每个线程往这个ThreadLocal中读写隔离的,并且是互相不会影响的。
一个ThreadLocal只能存储一个Object对象,如果需要存储多个Object对象那么就需要多个ThreadLocal!!!
如图:
看到上面的几个图,大概思路应该都清晰了,我们Entry的key指向ThreadLocal用虚线表示弱引用 ,下面我们来看看ThreadLocalMap:
java对象的引用包括 : 强引用,软引用,弱引用,虚引用 。
因为这里涉及到弱引用,简单说明下:
弱引用也是用来描述非必需对象的,当JVM进行垃圾回收时,无论内存是否充足,该对象仅仅被弱引用关联,那么就会被回收。
当仅仅只有ThreadLocalMap中的Entry的key指向ThreadLocal的时候,ThreadLocal会进行回收的!!!
ThreadLocal被垃圾回收后,在ThreadLocalMap里对应的Entry的键值会变成null,但是Entry是强引用,那么Entry里面存储的Object,并没有办法进行回收,所以ThreadLocalMap 做了一些额外的回收工作。
虽然做了但是也会存在内存泄漏风险(我没有遇到过,网上很多类似场景,所以会提到后面的ThreadLocal最佳实践!!!)
ThreadLocal的最佳实践!
ThreadLocal被垃圾回收后,在ThreadLocalMap里对应的Entry的键值会变成null,但是Entry是强引用,那么Entry里面存储的Object,并没有办法进行回收,所以ThreadLocalMap 做了一些额外的回收工作。
备注: 很多时候,我们都是用在线程池的场景,程序不停止,线程基本不会销毁!!!
由于线程的生命周期很长,如果我们往ThreadLocal里面set了很大很大的Object对象,虽然set、get等等方法在特定的条件会调用进行额外的清理,但是ThreadLocal被垃圾回收后,在ThreadLocalMap里对应的Entry的键值会变成null,但是后续在也没有操作set、get等方法了。
所以最佳实践,应该在我们不使用的时候,主动调用remove方法进行清理。
这里把ThreadLocal定义为static还有一个好处就是,由于ThreadLocal有强引用在,那么在ThreadLocalMap里对应的Entry的键会永远存在,那么执行remove的时候就可以正确进行定位到并且删除!!!
最佳实践做法应该为:
try {
// 其它业务逻辑
} finally {
threadLocal对象.remove();
}
思考
如果面试的时候,可以把上面的内容都可以讲到,个人觉得就非常好了,回答的就挺完美了。但是如果你可以进行下面的回答,那么就更完美了。
对于ThreadLocal,我在看Netty源码的时候,还了解过FastThreadLocal,xxxxx一些列内容,那就是一个升级了。
在我本地进行测试,FastThreadLocal的吞吐量是jdkThreadLocal的3倍左右。
备注: 由于FastThreadLocal内容也非常非常多,而且有很多技巧,所以准备后续专门在开一篇进行串起来!!!
**如果读完觉得有收获的话,欢迎点赞、关注、加公众号 [匠心零度] ,查阅更多精彩历史!!! **
手撕面试题ThreadLocal!!!的更多相关文章
- Netty实现高性能IOT服务器(Groza)之手撕MQTT协议篇上
前言 诞生及优势 MQTT由Andy Stanford-Clark(IBM)和Arlen Nipper(Eurotech,现为Cirrus Link)于1999年开发,用于监测穿越沙漠的石油管道.目标 ...
- 手撕RPC框架
手撕RPC 使用Netty+Zookeeper+Spring实现简易的RPC框架.阅读本文需要有一些Netty使用基础. 服务信息在网络传输,需要讲服务类进行序列化,服务端使用Spring作为容器.服 ...
- NN入门,手把手教你用Numpy手撕NN(一)
前言 这是一篇包含极少数学推导的NN入门文章 大概从今年4月份起就想着学一学NN,但是无奈平时时间不多,而且空闲时间都拿去做比赛或是看动漫去了,所以一拖再拖,直到这8月份才正式开始NN的学习. 这篇文 ...
- NN入门,手把手教你用Numpy手撕NN(2)
这是一篇包含较少数学推导的NN入门文章 上篇文章中简单介绍了如何手撕一个NN,但其中仍有可以改进的地方,将在这篇文章中进行完善. 误差反向传播 之前的NN计算梯度是利用数值微分法,虽容易实现,但是计算 ...
- 手撕公司SSO登陆原理
Single Sign-on SSO是老生常谈的话题了,但部分同学对SSO可能掌握的也是云里雾里,一知半解.本次手撕公司的SSO登陆原理,试图以一种简单,流畅的形式为你提供 有用的SSO登陆原理. 按 ...
- NN入门,手把手教你用Numpy手撕NN(三)
NN入门,手把手教你用Numpy手撕NN(3) 这是一篇包含极少数学的CNN入门文章 上篇文章中简单介绍了NN的反向传播,并利用反向传播实现了一个简单的NN,在这篇文章中将介绍一下CNN. CNN C ...
- 手撕代码:统计1到n二进制数中1出现的总次数
题目描述: 互娱手撕代码题. 统计从1到n这n个数的二进制表示中1出现的次数. 思路分析: 思路一:直接的做法是从1遍历到n,对于每个数和1做与操作,之后,对于这个数不断做右移操作,不断和1做与操作, ...
- 手撕ES6--Promise
手撕ES6--Promise:https://www.jianshu.com/p/0925eae38d2c 手写一个Promise,附源码分析:https://blog.csdn.net/weixin ...
- 几道JS代码手写面试题
几道JS代码手写面试题 (1) 高阶段函数实现AOP(面向切面编程) Function.prototype.before = function (beforefn) { let ...
随机推荐
- POJ 3276 枚举+差分?
题意: 思路: 先枚举一下k 贪心:如果当前是B那么就翻 差分一下序列 mod2 就OK了 //By SiriusRen #include <cstdio> #include <cs ...
- 开源计算机集群监控Ganglia应用视频
Ganglia源于Berkeley发起的一个开源集群监视项目,设计用于监测数上千节点的计算机集群.它包含gmond.gmetad以及一个Web前端.可以用来监控系统处理器 .内存.硬盘 I/O.网络流 ...
- HDU 4513 吉哥系列故事――完美队形II
http://acm.hdu.edu.cn/showproblem.php?pid=4513 吉哥系列故事——完美队形II Time Limit: 3000/1000 MS (Java/Others) ...
- 安装oracle常见问题分析
1,之前已经安装过软件,卸载不完全 /tmp/.oracle /tmp/ora* /var/tmp/ora* /etc/ora* 2,安装介质权限或者本身就有问题 3,oracle用户 $/HOME/ ...
- angular4自定义组件非input元素实现ngModel双向数据绑定
在angular里我们一般都是给input元素添加[(ngModel)]="value"实现数据双向绑定,如果想实现自定义的组件上实现ngModel双向数据绑定应该怎么办呐... ...
- 2017-2018年红头发新版Cisco认证网络工程师(CCNA-R&S)全新讲解分享
网名"红头发",多年授课经验,业内资深思科认证讲师,其所写的CISCO认证原创技术文章风靡各大网站与培训机构.精通CISCO各类路由交换产品,熟悉JUNIPER M/T系列路由产品 ...
- 紫书 例题 9-3 UVa 1347 ( 状态设计)
首先做一个转化,这种转化很常见. 题目里面讲要来回走一遍,所以就转化成两个从起点到终点,路径不重合 那么很容易想到用f[i][j]表示第一个走到i,第二个人走到j还需要走的距离 但是这里无法保证路径不 ...
- java8新增特性(一)---Lambda表达式
Lambda表达式也成为闭包,是java语言层次上的改变,Lambda同意把函数作为一个方法的參数(函数作为參数传递进方法中),或者把代码看成数据.函数式程序猿对这一概念非常熟悉. 在JVM平台上有非 ...
- 整理一些PHP开发安全问题
整理一些PHP开发安全问题 php给了开发人员极大的灵活性,可是这也为安全问题带来了潜在的隐患.最近须要总结一下以往的问题,在这里借翻译一篇文章同一时候加上自己开发的一些感触总结一下. 简单介绍 当开 ...
- centOS6.3(64bit)Hadoop的Eclipse开发环境搭建
操作系统centos6.3(64位) 一个namenode 两个datanode Hadoop版本号:hadoop-1.1.2 Eclipse版本号:eclipse-standard-kepler-S ...