HashMap在多线程下的死锁和覆盖原因

HashMap在jdk7之前,会产生死链和数据丢失这个问题

HashMap进行存储时,如果size超过当前最大容量*负载因子时候会发生resize,首先看一下resize原代码

void resize(int newCapacity) {
        Entry[] oldTable = table;
        int oldCapacity = oldTable.length;
        if (oldCapacity == MAXIMUM_CAPACITY) {
            threshold = Integer.MAX_VALUE;
            return;
        }
 
        Entry[] newTable = new Entry[newCapacity];
        transfer(newTable);
        table = newTable;
        threshold = (int)(newCapacity * loadFactor);
    }

而这段代码中又调用了transfer()方法,而这个方法实现的机制就是将每个链表转化到新链表,并且链表中的位置发生反转(因为源码在处理链表的时候,会依把遍历到的每个节点插在头结点位置处),而这在多线程情况下是很容易造成链表回路,从而发生get()死循环,我们看一下他的源代码

void transfer(Entry[] newTable) {
        Entry[] src = table;
        int newCapacity = newTable.length;
        for (int j = 0; j < src.length; j++) {
            Entry<K,V> e = src[j];
            if (e != null) {
                src[j] = null;
                do {
                    Entry<K,V> next = e.next;
                    int i = indexFor(e.hash, newCapacity);
                    e.next = newTable[i];
                    newTable[i] = e;
                    e = next;
                } while (e != null);
            }
        }
    }

那么为什么会产生死链呢?

在多线程情况下,假设有两个线程P1、P2,在扩容时操作HashMap,此时的链表为 a->b->null
1、P1先执行,执行完"Entry<K,V> next = e.next;"代码后发生阻塞,或者其他情况不再执行下去,此时e=a,next=b

2、而P2已经执行完整段代码,链表顺序会变为之前的倒序,于是当前的新链表newTable[i]为b->a->null

3、P1又继续执行"Entry<K,V> next = e.next;"之后的代码,则执行完"e=next;"后,即为让a指向b,但是线程P2中已经是b指向a了,那么newTable[i]为a<->b,则造成死链,while(e!=null)一直死循环

死链也可能由别的情况产生,这只是一种容易理解的。

还有数据丢失的情况,可以看下面的博客。

参考
https://www.cnblogs.com/xrq730/p/5037299.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值