【问题标题】:Why ThreadLocal use hash code, not array just like netty FastThreadLocal?为什么 ThreadLocal 使用哈希码,而不是像 netty FastThreadLocal 那样使用数组?
【发布时间】:2019-12-03 10:52:53
【问题描述】:
我正在阅读netty源代码,并将其与jdk源代码进行比较。
发现jdk在ThreadLocal中使用hash code,冲突多的时候比较慢。
那么为什么不用像netty中的FastThreadLocal一样使用数组,没有任何hash冲突,直接命中。
【问题讨论】:
标签:
concurrency
java-8
thread-local
【解决方案1】:
基于散列的方法可能“在有很多冲突时很慢”,但没有理由过早地假设存在很多冲突。由于“许多哈希冲突”是许多元素的标志,因此您所说的场景是线性索引方法存在更多问题。
FastThreadLocal 方法可能适用于积极使用它并创建使用它们的 FastThreadLocalThread 的特定实例的应用程序。
当 all 线程必须创建一个足够大的数组来保存 all ThreadLocal 曾经创建的实例的值时,这不会类似地工作。或者,更准确地说,一个数组通常更大,以避免每次创建 ThreadLocal 时都必须调整所有数组的大小。
您可以通过延迟扩展数组来降低成本,但这在为ThreadLocal #800 设置值时无济于事,因为索引小于该值的所有本地人都没有价值,甚至不再存在,因为此方案不支持自动清理。
ThreadLocal 实例可以自动收集垃圾,影响很小,这与必须遍历所有线程、重新排列它们的数组的清理方法无法相比。如果发生这种情况。我在FastThreadLocal 代码中找不到这样的清理方法。所以它似乎只是在增长。这对于标准的 JRE 解决方案显然是不可接受的。
【解决方案2】:
@Holger 你是对的。谢谢。
这几天看了JDK源码和netty源码,我想我明白为什么jdk用hash table而netty用common array了。
JDK 使用哈希表是因为当不再使用线程局部变量时,可以释放变量并调整哈希表的大小以避免内存泄漏。所以JDK使用WeakReference作为Entry来自动释放内存并使用0x61c88647来减少hash冲突。
但在netty中,为了搜索效率,它使用普通数组,不再自动释放内存。而netty可以手动删除一个线程的所有线程局部变量,只需使用removeAll()方法即可。