在多執行緒環境中,使用hashmap進行put操作時會引起死迴圈,導致cpu使用接近100%,下面通過**分析一下為什麼會發生死迴圈。
static class entryimplements map.entry、 }
/**之所以會導致hashmap出現死迴圈是因為多執行緒會導致hashmap的entry節點形成環鏈,這樣當遍歷集合時entry的next節點用於不為空,從而形成死迴圈* the table, resized as necessary. length must always be a power of two.
*/transient entry table;
單新增元素時會通過key的hash值確認鍊錶陣列下標
public v put(k key, v value)
}modcount++;
//新增鍊錶節點
addentry(hash, key, value, i);
return null;
}
下面看一下hashmap新增節點的實現
void addentry(int hash, k key, v value, int bucketindex)
以上部分的實現不會導致鏈路出現環鏈,環鏈一般會出現hashmap擴容是,下面看看擴容的實現:
void resize(int newcapacity)
entry newtable = new entry[newcapacity];
transfer(newtable);//可能導致環鏈
table = newtable;
threshold = (int)(newcapacity * loadfactor);
}
下面transfer的實現
void transfer(entry newtable) while (e != null);}}
}
這個方法的目的是將原鍊錶資料的陣列拷到新的鍊錶陣列中,拷貝過程中如果形成環鏈的呢?下面用乙個簡單的例子來說明一下:
public class infiniteloop ;
}.start();
new thread("thread2") ;
}.start();}}
下面通過debug跟蹤除錯來看看如果導致hashmap形成環鏈,斷點位置:
執行緒1的put操作
執行緒2的put操作
執行緒2的輸出操作
hashmap原始碼transfer方法中的第一行、第六行、第九行
測試開始
使執行緒1進入transfer方法第一行,此時map的結構如下
2. 使執行緒2進入transfer方法第一行,此時map的結構如下:
3.接著切換回執行緒1,執行到transfer的第六行,此時map的結構如下:
4.然後切換回執行緒2使其執行到transfer方法的第六行,此時map的結夠如上
5.接著切換回執行緒1使其執行到transfer方法的第九行,然後切換回執行緒2使其執行完,此時map的結構如下:
6.切換回執行緒1執行迴圈,因為執行緒1之前是停在hashmap的transfer方法的第九行處,所以此時transfer方法的節點e的key=3,e.next的key=7
void transfer(entry newtable) while (e != null);}}
}
下面執行緒1開始執行第一次迴圈,迴圈後的map結構如下:
接著執行第二次迴圈:e.key=7,e.next.key=3,e.next.next=null
接著執行第三次迴圈,從而導致環鏈形成,map結構如下
並且此時的map中還丟失了key=5的節點
java中怎麼遍歷HashMap
1.hashmap staff new hashmap 新增關鍵字值對,自己寫遍歷 set entries staff.entryset iterator iter entries.iterator while iter.hasnext 2.map map new hashmap for itera...
java中hashmap的作用
就是乙個鍵值對應的集合 hashmap a new hashmap a.put name abcdef key是name,value是字串abcdef system.out.println a.get name 根據key取得其值並輸出 list list new arraylist list.ad...
HashMap基礎與併發
執行緒不安全的hashmap,hashmap在併發執行put操作時會引起死迴圈,是因為多執行緒會導致hashmap的entry鍊錶形成環形資料結構,查詢時會陷入死迴圈。預設初始化大小為16,之後每次擴充,容量變為原來的2倍 預設載入因子為0.75 modcount作用 迭代器每修改一次就 1 has...