java中map丢失会怎么样_JDK1.7中HashMap导致的死链以及数据丢失问题

本文探讨了在并发环境下HashMap可能出现的死链和数据丢失问题。当HashMap进行扩容时,若多个线程同时操作可能导致死链,使得后续操作陷入死循环。此外,线程间的交错执行也可能造成数据丢失,因为线程私有的newTable会被后来的线程覆盖。理解这些问题对于避免并发编程中的隐患至关重要。
摘要由CSDN通过智能技术生成

简述

我们知道HashMap不支持并发,在并发情况下会有一系列问题产生,如形成死链和节点丢失,下面我们简单分析一下什么情况下会产生以及产生原因

死链问题

先贴一段源码

void transfer(Entry[] newTable, boolean rehash) {

int newCapacity = newTable.length;

for (Entry e : table) {

while(null != e) {

Entry next = e.next;//第一处

if (rehash) {

e.hash = null == e.key ? 0 : hash(e.key);

}

int i = indexFor(e.hash, newCapacity);

e.next = newTable[i];

newTable[i] = e;

e = next;

}

}

}

当HashMap需要扩容时,会调用上面的transfer方法将旧的元素重新计算hash值然后放入新的table里面

11c99bf29ad2

假设对以上table进行扩容(例子不是很准确,但可以说明问题)

按照transfer方法的逻辑,分为以下几个步骤

新的table容量为4

11c99bf29ad2

e.next = newTable[i],即将3的next指向newTable[i](刚开始为null),然后将3放在在newTable的对应位置上作为链表头,然后将e指向7

11c99bf29ad2

进入下次循环,同理将7的next指向newTable[i](即3),然后将7放在newTable的对应位置作为新的链表头,然后e指向5

11c99bf29ad2

继续循环,将5的next指向newTable[i](即null),然后将5放在newTable的对应位置作为新的链表头,然后e指向null,此为最后一次循环

11c99bf29ad2

可能会产生死链的情况

假设现在有两个线程A和B,按照以下顺序来执行transfer方法

A执行到源码第一处标识时,即此时e为3,next为7,cpu将资源让给了线程B

线程B将整个过程执行完,即得到最终结果如下图

11c99bf29ad2

此时对于原table来说,7指向了3,3指向了null,5指向了null,这时线程A继续运行,有以下步骤

3.1 此时对于线程A来说,e为3,next为7,将3放入指定位置,进行下次循环

3.2 此时e为7,保存7的next即3,然后将7指向3,进行下次循环

3.3 此时e为3,保存3的next即null,然后将3指向7,死链就此形成!

3.4 此时e为null,结束循环

后续调用put、get或者transfer时,如果命中此死链,将导致死循环!

分析时有个需要注意的点就是newTable属于局部变量,线程私有,两个线程的newTable是互相独立的,共享的只是Entry节点

节点丢失问题

假设一开始是如下所示

11c99bf29ad2

线程A和B存在如下顺序

线程A执行到第一处被挂起,此时e为3,next为5

线程B执行完,得到如下结果

11c99bf29ad2

此时线程A继续执行,将3放在指定位置,然后下次循环去放5,放完5由于5的next指向了null,故本次扩容结束,对于线程A和线程B,他俩有各自线程私有的newTable,其中A是正确的,但是线程A先执行了table=newTable进行赋值,线程B后执行,导致B覆盖了A,产生数据丢失

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值