说一说 hashmap 1

java.util.HashMap 基于 jdk 1.8

本篇我打算分以下三个点说

1 构造时传入的参数有什么卵用

2 头插法

3 并发下的扩容是怎么搞出环的

废话不多说。

1 构造的参数,根据源码,有两个可选

init capacity 所谓的初始容量 (IC)

load factor 所谓的加载因子 (LF)

构造的时候,一句话总结:

IC 会和 LF 相乘,弄出一个扩容的阈值 threshold 然后IC丢弃。注意,此时的threshold 并不发挥 扩容阈值的作用,具体下面说。

是的,通过反射查看 fields 你找不到 你传入的 IC。

进行展开,没兴趣的就不看了:

a IC会拿来进行一个有趣的算法,生成一个以IC最大bit开始 全bit位 为1的一个东西, 然后加上1 作为我们hashmap 的bucket 的length。 这个length做什么的,以后有机会再说。这个length,存放在threshold 的 field中。 (不懂为啥这样做,让人很混乱。瞎起名),这也是你唯一一次有机会看到你的bucket的数目,珍惜把。

b 你以为构造函数执行完之后,bucket就分配了?那你就错了。1.8的hashmap中, bucket采取了lazy loading策略, 只有在你构造完,使用put() 或者 size() 之类的方法的时候, 才会真正地进行内存的分配。threshold 这里第一次发挥作用,变为bucket 的 length 然后,就是熟悉的arr = new [length]。 最后,threshold 变为 length*LF, 也算是真正的threshold了。

c bucket[i] 是什么类型?你可以理解为链表节点。

2 头插法

首先为什么要头插法?因为链表一般人只保留头指针,你总不能O(n)找到链表尾部再来插入吧。

好的,头插法,一句话总结:新节点后接bucket[i],bucket[i]指向新节点。

不展开了,没什么好说的。

3

并发-》扩容-》成环

一句话总结:一个线程在获取current 和 next 了之后, 另外一个线程把这个next 放在了 current的前面。

这个我试着进行展开,而且无图:

1 线程A拿到了 节点n1 和 将n1的next 放在局部变量中,称为n2

2 线程B完成了一次扩容,因为是头插法,而且是从链表根部开始迁移,所以n2于是在 n1的前面

需要注意两个点

a. n1的next 是 NULL

b. n2的next 是 n1 

3 而线程A自己局部变量封闭的next 不是null,而是n2,线程A 把 bucket[i]指向n1,然后修改了n1的next为n2。到此为止。

n1.next指向 n2 且 n2.next指向 n1

 

 

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值