HashMap死迴圈問題追蹤

2021-08-15 19:37:58 字數 1936 閱讀 5102

hashmap在設計之初並沒有考慮多執行緒併發的情況,多執行緒併發的情況下理論上應該使用concurrenthashmap,但是程式中經常會無意中在多併發的情況下使用了hashmap,如果是jdk1.8以下的版本,有可能會導致死迴圈,打滿cpu占用,下面基於jdk1.7原始碼分析下原因。

我們從put看起

public v put(k key, v value) 

if (key == null)

return putfornullkey(value);

int hash = hash(key);

int i = indexfor(hash, table.length);

for (entrye = table[i]; e != null; e = e.next)

}modcount++;

addentry(hash, key, value, i);

return

null;

}

addentry方法長這樣:

void addentry(int hash, k key, v value, int bucketindex) 

createentry(hash, key, value, bucketindex);

}

下面就是resize方法:

void resize(int newcapacity) 

entry newtable = new entry[newcapacity];

transfer(newtable, inithashseedasneeded(newcapacity));

table = newtable;

threshold = (int)math.min(newcapacity * loadfactor, maximum_capacity + 1);

}

然後就是關鍵方法transfer:

void transfer(entry newtable, boolean rehash) 

int i = indexfor(e.hash, newcapacity);

e.next = newtable[i];

newtable[i] = e;

e = next;}}

}

thread1:

e=anext=b

舊鍊錶:

a->b->

null

新鍊錶:

null

thread1:

e=anext=b

舊鍊錶:

null

新鍊錶:

b->a->

null

thread1:

e=anext=b

舊鍊錶:

null

新鍊錶:

b->a->b(出現迴圈)

thread1:

e=anext=b

舊鍊錶:

null

新鍊錶:

a->b->a

thread1:

e=bnext=b

舊鍊錶:

null

新鍊錶:

a->b->a

那麼對於jdk1.8是如何做的呢,1.8的resize比較複雜,核心點在下面:

nodelohead = null, lotail = null;

nodehihead = null, hitail = null;

nodenext;

do else

} while ((e = next) != null);

HashMap擴容死迴圈問題解析

下面記錄了一下學習過程和自己的理解。當插入乙個新的鍵值對時,會先根據 key 對 hashmap底層陣列長度取模,得到鍵值對應該存放的陣列下標,然後呼叫 addentry 函式把這個鍵值對插入到這個下標所在的鍊錶中 void addentry int hash,k key,v value,int b...

多執行緒 HashMap 死迴圈 問題解析

原始碼resize void resize int newcapacity 複製 遷移 void transfer entry newtable while e null 複製 我們可以知道newtable 是新建立的 是執行緒私有的,因為 執行緒1 獲取 e 和next 之後 執行緒2 插入執行了...

HashMap 多執行緒 死迴圈 Java

hashmap,眾所周知,是執行緒不安全的。在多執行緒的情況下,在get 非常有可能出現死迴圈。因為 hashmap採用鍊錶解決hash衝突,因為是鍊錶結構,那麼就很容易形成閉合的鏈路,這樣在迴圈的時候只要有執行緒對這個hashmap進行get操作就會產生死迴圈。只 有乙個執行緒對hashmap的資...