今天在寫程序過程當中,須要根據判斷條件刪除一個Map中的相應數據,我天然而然想到能夠經過調用Map中的remove(Object key)函數進行刪除:代碼以下:java
public Map<Double, Double> processMap(Map<Double, Double> list) {算法
Map<Double, Double> map = list;數據結構
Iterator<Double> iter = map.keyset().iterator;多線程
while(iter.hasNext()) {函數
double key = iter.next();測試
if (key > 5).net
map.remove(key);線程
}指針
return map;對象
}
可是運行程序的時候卻沒有正常刪除元素,而是提示「Java.util.ConcurrentModificationException」錯誤,非常疑惑,於
是找了一些關於Map的資料發現:Map的實現不是同步的。若是程序中出現多個線程同時訪問一個Map,而其中至少一個線程修改Map
時,它必須保持外部同步。而經過查看Iterator原理髮現,Iterator是工做在一個獨立的線程中,而且擁有一個 mutex鎖,就是說
Iterator在工做的時候,是不容許被迭代的對象被改變的,因此調用Iterator操做得到的對象在多線程修改Map的時候會自動失效。
Iterator被建立的時候,創建了一個內存索引表(單鏈表),這 個索引表指向原來的對象,當原來的對象數量改變的時候,這個索
引表的內容沒有同步改變,因此當索引指針往下移動的時候,便找不到要迭代的對象,因而產生錯 誤。Map、List、Set等是動態
的,可變對象數量的數據結構,可是Iterator則是單向不可變,只能順序讀取,不能逆序操做的數據結構,當 Iterator指向的原始
數據發生變化時,Iterator本身就迷失了方向。
既然找到了問題的緣由,那麼如何解決呢?能夠經過調用Iterator的remove(Object o)函數來移除元素。
測試代碼以下:
public Map<Double, Double> processMap(Map<Double, Double> list) {
Map<Double, Double> map = list;
Iterator<Double> iter = map.keyset().iterator;
while(iter.hasNext()) {
double key = iter.next();
if (key > 5) {
// map.remove(key); // java.util.ConcurrentModificationException
iter.remove(key); // OK
}
}
return map;
}
同時,在遍歷Map過程當中,調用put(key, value)函數來添加元素,也會出現一樣的問題,因此一樣須要使用迭代器的相應函數來添加。