这玩意比ThreadLocal叼多了,吓得why哥赶紧分享出来。 (3)

简介: 这玩意比ThreadLocal叼多了,吓得why哥赶紧分享出来。 (3)

所以,其实线程上绑定的数据都是放到 InternalThreadLocalMap 里面的,不管你操作什么 ThreadLocal,实际上都是操作的 InternalThreadLocalMap。


那问题来了,你觉得一个叫做 fastGet ,一个叫做 slowGet。这个快慢,指的是 get 什么东西的快慢?


image.png


对咯,就是获取 InternalThreadLocalMap。


InternalThreadLocalMap 在 InternalThread 里面是一个变量维护的,可以直接通过 InternalThread.threadLocalMap() 获得:


image.png


标号为 ① 的地方是获取,标号为 ② 的地方是设置。


都是一步到位,操作起来非常的方便。


这是 fastGet。


而 slowGet 是从 ThreadLocal 中获取:


image.png


这里的 get ,就是原生 ThreadLocal 的 get 方法,一眼望去,就复杂多了:


image.png


标号为 ① 的地方,首先计算 hash 值,然后拿着 hash 值去数组里面取数据。如果取出来的数据不是我们想要的数据,则到标号为 ② 的逻辑里面去。


那么我问你,除了这个位置上的值真的为 null 外,还有什么原因会导致我拿着计算出来的 hash 值去数组里面取数据取不到?


image.png


就是看你熟不熟悉 ThreadLocal 对 hash 冲突的处理方式了。


那么这个问题稍微的升级一下就是:你知道哪些 hash 冲突的解决方案呢?


1.开放定址法。


2.链式地址法。


3.再哈希法。


4.建立公共溢出区。


我们非常熟悉的 HashMap 就是采用的链式地址法解决 hash 冲突。


而 ThreadLocal 用的就是开放定址法中的线性探测。


所谓线性探测就是,如果某个位置的值已经存在了,那么就在原来的值上往后加一个单位,直至不发生哈希冲突,就像这样的:


image.png


上面的动图就是需要在一个长度为 7 的数组里面,再放一个进过 hash 计算后为下标为 2 的数据,但是该位置上有值,也就是发生了 hash 冲突。


于是解决 hash 冲突的方法就是一次次的往后移,直到找到没有冲突的位置。


所以,当我们取值的时候如果发生了 hash 冲突也需要往后查询,这就是上面标号为 ③ 的 while 循环代码的其中一个目的。


当然还有其他目的,就隐藏在 440 行的 expungeStaleEntry 方法里面。不是本文重点,就不多说了。


但是如果你不知道这个方法,你一定要去查阅一下相关的资料,有可能会在一定程度上改变你印象中的:用 ThreadLocal 会导致内存泄漏的风险。


至少,你可以知道 JDK 为了避免内存泄漏的问题,是做了自己的最大努力的。


好了,不扯远了,说回来。


从上面我们知道了,从 ThreadLocal 中获取 InternalThreadLocalMap 会经历如下步骤:


1.计算 hash 值。


2.判断通过 hash 值是否能直接获取到目标对象。


3.如果没有获取到目标对象则往后遍历,直至获取成功或者循环结束。


比从 InternalThread 里面获取 InternalThreadLocalMap 复杂多了。


现在你知道了 fastGet/slowGet 这个两个方法中的快慢,指的是从两个不同的 ThreadLocal 中获取 InternalThreadLocalMap 的操作的快慢。而快慢的根本原因是数据结构的差异。


好,现在我们获取到 InternalThreadLocalMap 了,接着看 set 方法:


image.png

目录
相关文章
|
7月前
|
Java 应用服务中间件 Spring
ThreadLocal 的使用及踩坑
ThreadLocal 的使用及踩坑
48 1
面试又被问懵了吗?不如把ThreadLocal拆开了揉碎看看
1.为什么用 ThreadLocal? 所谓并发,就是有限资源需要应对远超资源的访问。解决问题的方法,要么增加资源应对访问;要么增加资源的利用率。 所以,相信这年头做开发的多多少少,都会那么几个“线程二三招”、“用锁五六式”。 那所带来的就是多线程访问下的并发安全问题。 共享变量的访问域跨越了原始的单线程,进入了千家万户的线程眼里。谁都可以用,谁都可以改,那不就打起来了吗? 因此,防止并发问题的最好办法,就是不要多线程访问(这科技水平倒退二十年~)。ThreadLocal 顾名思义,将一个变量限制为“线程封闭”:对象只被一个线程持有、访问、修改。
|
存储 缓存 Java
终于弄明白了ThreadLocal
ThreadLocal是Thread的局部变量,用于编多线程程序,对解决多线程程序的并发问题有一定的启示作用。
113 0
终于弄明白了ThreadLocal
|
存储 安全 程序员
看完这篇 HashMap ,和面试官扯皮就没问题了(1)
看完这篇 HashMap ,和面试官扯皮就没问题了(1)
108 0
看完这篇 HashMap ,和面试官扯皮就没问题了(1)
|
存储 Java Serverless
看完这篇 HashMap ,和面试官扯皮就没问题了(3)
看完这篇 HashMap ,和面试官扯皮就没问题了(3)
80 0
看完这篇 HashMap ,和面试官扯皮就没问题了(3)
|
存储 Java
看完这篇 HashMap ,和面试官扯皮就没问题了(2)
看完这篇 HashMap ,和面试官扯皮就没问题了(2)
89 0
看完这篇 HashMap ,和面试官扯皮就没问题了(2)
|
存储 安全 Java
看完这篇 HashMap ,和面试官扯皮就没问题了(4)
看完这篇 HashMap ,和面试官扯皮就没问题了(4)
63 0
看完这篇 HashMap ,和面试官扯皮就没问题了(4)
|
算法 安全 Java
threadlocal再温习
早时总结过《ThreadLocal解析》、《FastThreadLocal解析》 最近看一些资料的时候,又重重发现了这类,不希望再温下,许多知识点,之前已经总结了,这篇文章主要有两个问题: 1、弱引用的意义 2、如何防键冲突
199 0
threadlocal再温习
烧点脑子使劲看--HashMap源码分析(下)
构造方法 HashMap一共有四个构造
99 0
|
安全
烧点脑子使劲看--HashMap源码分析(上)
概述 HashMap最早出现在JDK1.2中,是基于Map接口的实现,储存的内容是键值对(key-value),HashMap中的键和值都可以为null。HashMap的实现并不是同步的,也就是说它不是线程安全的。
79 0