2016-05-11 103 views
1

當我迭代map(HashMap,HashTable,ConcurrentHashMap)時,當我嘗試刪除特定條目時,它仍然在迭代中打印它值。但是每一個入口都不會發生這種情況。雖然在地圖上迭代,但對於某個值,雖然它已被刪除,但它已被打印

public class Test { 
    public static void main(String[] args) { 
     ConcurrentHashMap<String, String> map = new ConcurrentHashMap<String, String>(); 
     map.put("Pujan", "pujan"); 
     map.put("Swati", "swati"); 
     map.put("Manish", "manish"); 
     map.put("Jayant", "pujan"); 
     System.out.println(map); 

     for (String string : map.keySet()) { 
     System.out.println(string+","+map.get(string)); 
     map.remove("Manish"); 
     } 
     System.out.println(map); 
    } 
    } 

輸出:

{Jayant=pujan, Swati=swati, Manish=manish, Pujan=pujan} 
Jayant,pujan 
Swati,swati 
Pujan,pujan 
{Jayant=pujan, Swati=swati, Pujan=pujan} 

??二Scenarion

//map.remove("Manish"); 
map.remove("Swati"); 

輸出:

{Jayant=pujan, Swati=swati, Manish=manish, Pujan=pujan} 
Jayant,pujan 
**Swati,null** 
Manish,manish 
Pujan,pujan 
{Jayant=pujan, Manish=manish, Pujan=pujan} 
+0

爲什麼'map.remove'在'for'循環中? – piyushj

+0

迭代時,你絕對不應該使用'Map.remove'。大多數時候你會得到一個併發修改異常,如果沒有,你會得到不可預知的結果。 – RealSkeptic

+0

@RealSkeptic - 他正在使用ConcurrentHashMap! –

回答

1

ConcurrentHashMapkeySet方法返回KeySetView其有一個weakly consistentiterator,換句話說,它返回iterator是該集創建時的快照。

ConcurrentHashMap#keySet() Java文檔

視圖的迭代器和spliterators是弱一致

但是,當你調用map.get的變化是顯而易見的,這意味着map.get將返回null,因爲你請求一個不存在的密鑰

1

查看keySet()的JavaDocs(假設Java8)[https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html#keySet--][1]

返回此映射中包含的鍵的Set視圖。該集合由地圖支持,因此對地圖的更改反映在集合中,反之亦然。該集支持元素刪除,通過Iterator.remove,Set.remove,removeAll,retainAll和clear操作從該映射中刪除相應的映射。它不支持add或addAll操作。

視圖的迭代器和分割器是弱一致的。

哪個環節:

他們保證,他們在施工中存在恰好一次遍歷元素,並且可能(但並不保證)反映構造後的任何修改。

這就是你所看到的。

管理for循環的迭代器不能保證在構建視圖後反映更改。

該視圖總是由4個原始條目構建而成。現在,在「Manish」的例子中,恰巧迭代器確實反映了修改,所以字符串永遠不會將Manish作爲值,並且您永遠不會執行map.get("Manish")。唉,使用Swati迭代器並沒有反映修改,它仍然給你「Swati」作爲第二個元素,儘管數據總是一致的:根據JavaDocs,map.get("Swati")確實反映了這種變化。

我還沒有閱讀ConcurrentHashMap.MapEntry(你應該)的代碼,但是爲什麼發生這種情況與「Swati」而不是「Manish」很可能是下面的內容。

  • 迭代器已創建。狀態:next =「Jayan」,節點= [「Swati」,「Manish」,「Pujan」]
  • iterator.next()。返回「Jayan」。州:未來= 「斯瓦特」,節點= [ 「馬尼什」, 「Pujan」]

在這一點上,做iterator.next()將返回current = 「姆斯瓦蒂」(evne元素是否來自不見了該地圖隨後顯示map.get()

如果刪除「Manish」(或「Pujan」),則迭代器可以更新nodes。但是,如果刪除「Swati」,則已經太遲,因爲current已經加載了該密鑰。

相關問題