今天在寫程序過程中,需要根據判斷條件刪除一個Map中的相應數據,我自然而然想到可以通過調用Map中的remove(Object key)函數進行刪除:代碼如下:
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);
}
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)函數來添加元素,也會出現同樣的問題,所以同樣需要使用迭代器的相應函數來添加。
