ThreadLocalMap 、ThreadLocal 、Entry 和线程之间的关系(通俗易懂、且详细)

1.一个通俗的比喻

  • 线程(Thread):好比去健身房锻炼的用户,每个人有一个自己的大储物柜ThreadLocalMap

  • ThreadLocalMap:用户的储物柜,上面有多个抽屉。

  • ThreadLocal实例:储物柜上抽屉的钥匙;一个实例就是一个钥匙,对应一个抽屉;钥匙是公共的,但用户只能拿该钥匙去打开自己的抽屉。

  • Entry:储物柜上的抽屉(抽屉上有对应钥匙的编号)。

2. 关系拆解

① 用户和储物柜
  • 每个用户(线程)都有一个储物柜(ThreadLocalMap)

  • ThreadLocalMap是线程私有的,不允许其他线程访问。

② 储物柜和抽屉
  • 储物柜(ThreadLocalMap)上有很多抽屉(Entry数组)——>ThreadLocalMap是一个Entry数组

  • 每个抽屉里存放一个物品(值),抽屉上贴着钥匙的编号(ThreadLocal实例)

也就是说,Entry类其实封装着一个键值对,Key是ThreadLocal实例,value是存储的值;

static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
     Object value;

     Entry(ThreadLocal<?> k, Object v) {
         super(k);
         value = v;
     }
}
③ 钥匙和抽屉
  • 用户用钥匙(ThreadLocal实例)打开储物柜里的对应抽屉

  • 不同用户用同一把钥匙,打开的其实是各自储物柜里对应的抽屉,互不影响!

3. 其他设计细节

为什么用弱引用(WeakReference)?
  • Entry的Key(ThreadLocal)是弱引用

    • 如果lockerKey1在代码中被置为null,垃圾回收时,Entry中的Key会被清除(防止内存泄漏)。

    • 但Value仍是强引用,所以必须手动调用remove()清理!(否则Value可能一直存在)

哈希冲突解决
  • ThreadLocalMap使用开放寻址法(而非HashMap的链表):

    • 如果抽屉被占用了(发生哈希冲突),就往后继续遍历数组,找下一个空抽屉。

    • 取数据时,先找到初始位置,再线性探测。

总结

        简单来说,就是对于同一个ThreadLocal对象,以它作为键(Key),在不同线程的ThreadLocalMap中存储的值是不同的。

        因此实现了在 Java 里,ThreadLocal类为每个使用该变量的线程都单独创建一个独立的副本,每个线程都能独立地改变自己的副本,而不会影响其他线程所对应的副本。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值