首页 > 代码库 > HashMap在高并发下引起的死循环

HashMap在高并发下引起的死循环

HashMap其实并不是线程安全的,在高并发的情况下,是很可能发生死循环的,由此造成CPU 100%,这是很可怕的,所以在多线程的情况下,用HashMap是很不妥当的行为,应采用线程安全类ConcurrentHashMap进行代替。


HashMap死循环原因

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 = http://www.mamicode.com/table;>

HashMap死循环演示

假如有两个线程P1、P2,以及链表 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;"后,newTable[i]为a《=》b,则造成回路,while(e!=null)一直死循环


总结

HashMap并非线程安全,所以在多线程情况下,应该首先考虑用ConcurrentHashMap,避免悲剧的发生




HashMap在高并发下引起的死循环