图解JDK7中的HashMap闭环和丢失问题

关于HashMap的线程安全问题,网上资料很多。对于1.7版本的闭环问题,看了很多网上的资料一直搞不懂,今天又琢磨了一下,终于明白了,用自己看得懂的方式记录下。

首先说下闭环产生的原因:1.7的HashMap在扩容复制时,采用的是头插入法,这会导致原数组中的链表反转,即将原来的正向,复制成反向链表。
而在多线程环境下,可能存在其他线程完成了扩容复制操作,完成了后的数组链表变成了原来的反向链表。
由于可见性的保证,当前线程继续复制时,复制的时其他线程已经完成了的反向链表,但当前线程又会将其反转,导致又变成了正向链表,那么在当前线程复制过程中会既有正向的链表又有反向的链表,从而可能产生闭环的情况。
具体的图例如下
左边的为扩容前的分布,右边的为正常单线程情况下完成复制后的情况。
在这里插入图片描述
首先说下头插入的过程,首先遍历旧数组链表,拿到第一个元素A,保存其后续链表B,然后计算在新数组位置1并拿到首节点NULL,将A的next设置为NULL
在这里插入图片描述
将A放入新数组对应位置中
在这里插入图片描述
将原后续链表续到原数组中
在这里插入图片描述
以上是正常的移动过程,现在分析并发场景下产生的闭环问题和丢失问题

闭环问题

  1. 线程1执行到这里后挂起
    在这里插入图片描述
  2. 线程2完成复制工作如下如
    在这里插入图片描述
  3. 线程1唤醒,继续操作,由于可见性,老数组中的B的next实际上已经变成了A,线程1此时会将A至于新数组索引1中,即虚线框会发送覆盖
    在这里插入图片描述
  4. 覆盖后变成下图
    在这里插入图片描述
  5. 继续完成B的复制,如下图
    在这里插入图片描述
  6. 旧数组中还剩下一个A,继续。还记得前面移动的步骤,首先会变更A的next指向B,然后放入新数组中。
    在这里插入图片描述
  7. 最终会成为下图形成闭环
    在这里插入图片描述

丢失

  1. 线程1在此处挂起
    在这里插入图片描述
  2. 线程2完成复制,如下图
    在这里插入图片描述
  3. 线程1苏醒,完成A的复制,此时B的next已经变成了NULL,C丢失
    在这里插入图片描述
  4. 复制B,C没了
    在这里插入图片描述

1.8尾插入发

由上面可知,丢失和闭环均是由于改变链表方向导致的,设计者一开始使用头插入法是考虑碰撞时后加入的数据访问的可能性更大,头插入有更好的查找性能。
1.8改为尾插入,不会进行链表方向的改变,因此不会发生上面两种情况

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值