• 中文
    • English
  • 注册
  • 查看作者
  • JAVA concurrency — ThreadLocal 源码详解

    概述

    在并发编程中,为了控制数据的正确性,我们往往需要使用锁来来保证代码块的执行隔离性。但是在很多时候锁的开销太大了,而在某些情况下,我们的局部变量是线程私有的,每个线程都会有自己的独自的变量,这个时候我们可以不对这部分数据进行加锁操作。于是
    应运而生。

    顾名思义,是线程持有的本地变量,存放在
    中的变量不会同步到其他线程以及主线程,所有线程对于其他的线程变量都是不可见的。那么我们来看下它是如何实现的吧。

    实现原理

    在内部实现了一个静态类
    来对于变量进行存储,并且在
    类的内部使用到了这两个成员变量

    来调用
    存储当前线程的内部变量。

    ThreadLocalMap的实现

    是键值对结构的map,但是他没有直接使用
    ,而是自己实现了一个。

    Entry


    中定义的map节点,他以
    弱引用为key,以Object为value的
    形式的节点。使用弱引用是为了可以及时释放内存避免内存泄漏。

    这里和
    不一样的地方在于两者解决hash冲突的方式的不同,
    采用的是链地址法,遇到冲突的时候将冲突的数据放入同一链表之中,等到链表到了一定程度再将链表转化为红黑树。而
    实现采用的是开放寻址法,它内部没有使用链表结构,因此
    内部没有next或者是prev指针。
    的开放寻址法是怎么实现的,请看接下来的源码。

    成员变量

    这里的数组大小始终是2的幂次,原因和
    一样,是为了在计算hash偏移的时候减少碰撞。

    构造函数

    set方法

    看到这段代码,开放寻址法的实现原理可以说是非常清楚了。首先计算节点的hash值,找到对应的位置,查看该位置是否为空,如果是空则插入,如果不为空,则顺延至下个节点,直到找到空的位置插入。那么我们的查询逻辑也呼之欲出:计算节点的hash值,找到对应的位置,查看该节点是否是我们想要找的节点,如果不是,则继续往下顺序寻找。

    get方法

    replaceStaleEntry

    expungeStaleEntry

    cleanSomeSlots

    rehash

    expungeStaleEntries

    关于Map的清理

    实现采用的是开放寻址法,它的实现本身应该是比较简洁的,但是为了便于GC,内部节点采用了弱引用作为key,一旦数组中节点的强引用被设置为了null,节点的key就会被gc自动回收。这样导致了
    的实现变得异常的复杂。为了防止内存泄漏,在get和set方法的时候不得不进行额外的清理。

    Q 为什么需要清理?

    A 不清理的话key被回收,但是value依旧会存在,并且难以被回收导致内存泄漏。

    Q 为什么清理的时候会涉及到节点的移动?

    A 因为在开放寻址法中,可能会有相同hash值的节点连续排在一起,当其中的一个或多个节点被回收后会造成同hash值的节点中间存在null节点,而我们get节点的时候会在碰到空节点的时候停止寻找,所以如果不进行一定的清理移动会导致部分节点永远不会被查询到。

    ThreadLocal的实现

    hashcode的实现

    讲完了
    的实现原理,我们可以深深的体会到

    是多么的重要,如果hash值不能够以合理的方式生成,导致数据的分布不均匀,
    的效率将会非常的低下。

    hashcode的实现:


    实现代码很简短:每一个新的
    的hash值都是在
    的基础上增加
    。实现很简单,但是很让人迷惑。这个莫名其妙的魔数
    是什么?

    是有斐波那契构造而成的黄金比例数字,经过实验测试,这个数字生成的hashcode可以很大程度的保证hash值能够在数组中均匀的分布。

    get

    set

    总结

    这个类可能对于很多人来说是一个常常会用到的类,但是未必所有人都会去关注他的内部实现,但是他的源码是比较值得去阅读的,一来它的实现代码相对其他的常用类很短,只有几百行;二来它的实现很经典,经典的开放寻址法,经典的弱引用方便GC,可以说是很好的学习材料。

    这里我虽然对于整个
    的源码进行了完整的注释解释,但是它最值得细细品味的还是它的设计理念以及设计思路,这会对我们写出优秀的代码有着重要的作用。

  • 0
  • 0
  • 0
  • 26
  • 请登录之后再进行评论

    登录
  • 任务
  • 实时动态
  • 发布
  • 单栏布局 侧栏位置: