多线程环境下HashMap之死循环
众所周知,HashMap是非线程安全的,多线程下一般使用ConcurrentHashMap代替,那为什么HashMap在多线程下不安全呢?ConcurrentHashMap又是如何改进的?
为什么HashMap在多线程先不安全
HashMap 在多线程环境下可能会发生死循环
看过HashMap(jdk1.6)的put方法源码的人都知道,在put数据时有可能会触发table表的扩容,调用的方法是resize方法,在resize方法中会新建一个更大的hash表,然后将老的的数据迁移到新表中,迁移时用到的方法是transfer,下面附上transfer方法的源代码:
void transfer(Entry[] newTable)
{
Entry[] src = table;
int newCapacity = newTable.length;
for(intj = 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);
}
}
}
现在有俩个线程,在put时都触发了扩容机制,线程一执行到标记①挂起了,此时的hash表情况如下:
线程二继续执行,两轮循环后:
此时线程二挂起,线程一继续执行:
线程一执行一轮循环后:
此时出现了循环链表,线程一陷入死循环,所以HashMap不适合在多线程场景下使用。
ConcurrentHashMap(jdk1.6)又是如何改进的
V put(K key, int hash, V value, boolean onlyIfAbsent) {
//标记①
lock();
try {
int c = count;
if (c++ > threshold) // ensure capacity
rehash();
HashEntry<K,V>[] tab = table;
int index = hash & (tab.length - 1);
HashEntry<K,V> first = tab[in