ThreadLocal原理记录,别被坑了!!
简介
ThreadLocal的用处
ThreadLocal是为了将数据记录一份到某个线程里,确保该数据线程安全
例如数据库的Connection放入ThreadLocal,一个事务会用到很多DAO,但只能用共同的Connection,这样才能保证事务完整性
所以当某个类的其中一个变量,会被同一个线程多次使用,并且还严格的规定每次都得是这个变量操作
那么就能把这个变量放入ThreadLocal
Spring也是将各种Bean放入ThreadLocal中来确保Bean的“无状态”化
吐槽开始!!
今天翻书看了关于ThreadLocal的介绍,和网上一些关于ThreadLocal的博客,这个原理介绍真的是坑,大错特错
大家可能都看到过下面这种所谓的ThreadLocal简单的实现思路介绍:
完了后还加上一句:
虽然上面的代码清单中的这个ThreadLocal实现版本显得比较简单粗爆,但其目的主要在与呈现JDK中所提供的ThreadLocal类在实现上的思路
上面这样简化ThreadLocal实现根本错的离谱
不仅是有的博客这样,包括书本也是这样介绍的,传播知识给他人,的确可以简化代码实现,但不等于更改了正确的实现思路!
这样会误导他人对ThreadLocal的进一步学习
ThreadLocal真正的实现方式
先说总结,跟上面错误做对比
1.ThreadLocalMap 别看有个Map结尾,其实压根就是重新实现的类
跟Map没半毛钱关系,没实现Map接口的,没用HashMap,别觉得根据key找value就只能使用map了
2.线程根据key找对应的value,这个key并不是线程id,而是ThreadLocal类
为什么,因为ThreadLocalMap是存放在线程里的,每个线程都只有一个只属于自己的ThreadLocalMap
这样的话存个毛的线程id,有什么意义?
揭开Thread,ThreadLocal,ThreadLocalMap真正的关系
首先进入ThreadLocal,发现如下
ThreadLocalMap实在ThreadLocal里实现的
直接找到ThreadLocal的set()方法
public void set(T value) {
Thread t = Thread.currentThread(); //获得当前线程
ThreadLocalMap map = getMap(t); //将当前线程作为参数传入,来获取ThreadLocalMap
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
然后进入getMap()方法
ThreadLocalMap getMap(Thread t) {
return t.threadLocals; //追踪后发现t.threadLocals就是 ThreadLocal.ThreadLocalMap threadLocals;
}
如果得到的map为null,那么说明是第一次,走createMap方法创建
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue); //看到了吧,ThreadLocalMap直接是给Thread保存的
}
进入new ThreadLocalMap方法,这里注意,传入的this就是指ThreadLocal
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) { //看到参数名字没,firstKey,ThreadLocal传进来是当作key值的!
table = new Entry[INITIAL_CAPACITY]; //table其实是private Entry[] table; 一个数组而已
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY);
}
ThreadLocalMap没有实现Map接口,跟Map没半毛钱关系,至于Entry是什么,我们看看
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value; Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
首先WeakReference是指弱引用的意思,继承了这玩意有以下效果:
当一个对象仅仅被weak reference(弱引用)指向, 而没有任何其他strong reference(强引用)指向的时候, 如果这时GC运行, 那么这个对象就会被回收,不论当前的内存空间是否足够,这个对象都会被回收。
好处在于,如果某个ThreadLocal被回收了,那么ThreadLocalMap的这个Key在下次GC()的时候也会被回收(不然就造成内存泄露了,这个key永远不会被调用)
Entry是一个ThreadLocalMap的内部类,跟Map的Entry实现有点像,有key和value的定义(俗称 桶)
ok,我们发现,ThreadLocalMap创建后,就是初始化一个Entry的数组,生成一个Entry将ThreadLocal作为key值,将要存的值作为value放入其中存好
那么假设现在ThreadLocalMap已经存在,走的是第一个分支,直接set,我们看看他怎么实现的
1 private void set(ThreadLocal<?> key, Object value) {
2
3 Entry[] tab = table;
4 int len = tab.length;
5 int i = key.threadLocalHashCode & (len-1);
6
7 for (Entry e = tab[i];
8 e != null;
9 e = tab[i = nextIndex(i, len)]) {
10 ThreadLocal<?> k = e.get();
11
12 if (k == key) {
13 e.value = value;
14 return;
15 }
16
17 if (k == null) {
18 replaceStaleEntry(key, value, i);
19 return;
20 }
21 }
22
23 tab[i] = new Entry(key, value);
24 int sz = ++size;
25 if (!cleanSomeSlots(i, sz) && sz >= threshold)
26 rehash();
27 }
看到第7行的for没有,直接遍历方才说的Entry数组,将ThreadLocal取出来比较(相当于key比较),匹配就设置value,没这个key就存起来
ThreadLocalMap为啥不用HashMap而是自己数组实现
有key和value这个概念出现,也不是一定要用HashMap这些的,为什么用数组
个人觉得是省开销,创建Map对象的开销和使用Map的开销,毕竟ThreadLocalMap初始默认长度为16,而真实情况中一个线程不会有这么本地变量要保存
所以,当使用ThreadLocal来存的时候,ThreadLocal会创建一个ThreadLocalMap给调用它的线程,自己作为key值去保存
取值的时候,ThreadLocal拿Thread里保存的ThreadLocal,然后将自身作为key值去取值
为什么ThreadLocalMap的代码不放在Thread中
网上有个答案我觉得很合理:
将ThreadLocalMap定义在Thread类内部看起来更符合逻辑
但是ThreadLocalMap并不需要Thread对象来操作,所以定义在Thread类内只会增加一些不必要的开销。
定义在ThreadLocal类中的原因是ThreadLocal类负责ThreadLocalMap的创建和使用
总的来说就是,ThreadLocalMap不是必需品,定义在Thread中增加了成本,定义在ThreadLocal中按需创建。
线程不一定都用到ThreadLocal的哦,如果不使用,就不会被赋值一个ThreadLocalMap
换个思维,这其实也是种不错的设计模式:
一个工具类把自身当作唯一标识,去操作工具类本身的方法,只需要将数据记录给调用它的类就好
ThreadLocal的内存泄露问题
正常来说,我们创建一个线程,跑完后会销毁,自动调用ThreadLocal的remove()方法,清除ThreadLocalMap的内容
但是,实际中我们是使用线程池的,而线程跑完后会返回线程池中,并不会销毁
这时候的ThreadLocalMap的内容就还在的(内存就是这里泄露啦)
所以,在线程池中用ThreadLocal,记得run()要跑完时用下remove()方法清除ThreadLocalMap中的key
至此分享完毕啦,希望大家点点赞,或者一键3连不迷路~~
ThreadLocal原理记录,别被坑了!!的更多相关文章
- ThreadLocal原理及其实际应用
前言 java猿在面试中,经常会被问到1个问题: java实现同步有哪几种方式? 大家一般都会回答使用synchronized, 那么还有其他方式吗? 答案是肯定的, 另外一种方式也就是本文要说的Th ...
- ThreadLocal学习记录
ThreadLocal简介 当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的 ...
- java基础解析系列(七)---ThreadLocal原理分析
java基础解析系列(七)---ThreadLocal原理分析 目录 java基础解析系列(一)---String.StringBuffer.StringBuilder java基础解析系列(二)-- ...
- 简析ThreadLocal原理及应用
简析ThreadLocal原理及应用 原创: 东晨雨 JAVA万维猿圈 4月17日 ThreadLocal的源码加上注释不超过八百行,源码结构清晰,代码也比较简洁.ThreadLocal可以说是Jav ...
- ThreadLocal原理简单刨析
ThreadLocal原理简单刨析 ThreadLocal实现了各个线程的数据隔离,要知道数据是如何隔离的,就要从源代码分析. ThreadLocal原理 需要提前说明的是:ThreadLocal只是 ...
- ThreadLocal 原理和使用场景分析
ThreadLocal 不知道大家有没有用过,但至少听说过,今天主要记录一下 ThreadLocal 的原理和使用场景. 使用场景 直接定位到 ThreadLocal 的源码,可以看到源码注释中有很清 ...
- ThreadLocal原理分析与使用场景
什么是ThreadLocal变量 ThreadLoal 变量,线程局部变量,同一个 ThreadLocal 所包含的对象,在不同的 Thread 中有不同的副本.这里有几点需要注意: 因为每个 Thr ...
- 03、Swagger2和Springmvc整合详细记录(爬坑记录)
时间 内容 备注 2018年6月18日 基本使用 spirngmvc整合swagger2 开始之前这个系列博文基本是,在项目的使用中一些模块的内容记录,但是后期逐渐优化,不单单是整合内容. swagg ...
- ThreadLocal原理分析
本文结构 ThreadLocal简介 (简要说明ThreadLocal的作用) ThreadLocal实现原理(说明ThreadLocal的常用方法和原理) ThreadLocalMap的实现 (说明 ...
随机推荐
- 315. Count of Smaller Numbers After Self(二分或者算法导论中的归并求逆序数对)
You are given an integer array nums and you have to return a new counts array. The counts array has ...
- C#高级编程之泛型二(泛型类型约束、类型、反射与泛型)
泛型类型约束 简言之:对泛型类型进行约束,细化,限定. MSDN的定义:泛型定义中的 where 子句指定对用作泛型类型.方法.委托或本地函数中类型参数的参数类型的约束,意思就是可以有泛型类.泛型方法 ...
- 【鸿蒙开发板试用报告】用OLED板实现FlappyBird小游戏(上)
总是做各种Demo,是时候做个什么小应用来练练手了.踌躇了很久,果然还是搞个小游戏才有意思.想到几年前风靡全球的FlappyBird,一个屏幕一个按钮就足够了,正好适合.OLED屏幕.按键的驱动已经有 ...
- FTP漏洞利用复现
目录 FTP弱口令漏洞 FTP后门漏洞利用 FTP弱口令漏洞 漏洞描述 FTP弱口令或匿名登录漏洞,一般指使用FTP的用户启用了匿名登录功能,或系统口令的长度太短.复杂度不够.仅包含数字.或仅包含字母 ...
- vue项目中h5移动端中通过flex布局实现首尾固定,中间滚动(借鉴)
html中 <div class="flexLayoutr"> <div class="div_head"></div> & ...
- java开发三年,Java中接口的使用你得知道,不然你凭什么涨薪
接口概述: 接口是Java语言中的一种引用类型,是方法的"集合",所以接口的内部主要就是定义方法,包含常量,抽象方法(JDK 7及以前),额外增加默认方法和静态方法(JDK 8), ...
- 新鲜出炉!2020年最新java面试题大全,面试突击必备!
前言 发现网上很多Java面试题都没有答案,所以花了很长时间搜集整理出来了一套Java面试题,希望对大家有帮助哈~ 打算这几天每天更新15~20题.(这样有助于你们阅读和理解!)我们先从简单的开始 1 ...
- 今天谁也别想阻止我好好学习!「CDR 6·18特惠倒计时2天!」
前几天小编刷抖音,一个以农夫山泉为创作背景的服装原创视频 让我为之一震 这个自称以捡瓶子为生的服装设计师 让我产生了极为浓烈的兴趣 细扒这位小姐姐的视频 她用身边的常见物品 脑洞大开的画出了一系列插画 ...
- 左右声道音频怎么制作,用Vegas就对啦
一款优秀的视频剪辑软件,不仅有高水平的视频制作功能,它的音频编辑功能也是必不可少的.Vegas就是这么一款软件,同时具备视频制作特效制作的同时,还能帮助制作轨道音频效果. 下面,就让小编带大家去学习, ...
- 从这三方面优化你的电脑,保持Mac运行流畅
使用着Mac系统的用户都知道,Mac OS的各方面性能都很好,特别是流畅性,有人说不用清理垃圾也能流畅地使用Mac,但这的确是夸张了.电脑使用的时间长了,它的性能总会越来越退步,这其中有着系统垃圾拖累 ...