Reputation: 169
When I iterate over map (HashMap,HashTable,ConcurrentHashMap), when I try to remove particular entry, in iteration it still prints it with null value. But it does not happen with every entry.
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);
}
}
output:
{Jayant=pujan, Swati=swati, Manish=manish, Pujan=pujan}
Jayant,pujan
Swati,swati
Pujan,pujan
{Jayant=pujan, Swati=swati, Pujan=pujan}
??Second Scenarion
//map.remove("Manish");
map.remove("Swati");
Output:
{Jayant=pujan, Swati=swati, Manish=manish, Pujan=pujan}
Jayant,pujan
**Swati,null**
Manish,manish
Pujan,pujan
{Jayant=pujan, Manish=manish, Pujan=pujan}
Upvotes: 1
Views: 103
Reputation: 23329
The keySet
method in ConcurrentHashMap
returns a KeySetView
which has a weakly consistent iterator
, in other words, the iterator
it returns is a snapshot of the set at the time it's created.
From the ConcurrentHashMap#keySet()
Java docs
The view's iterators and spliterators are weakly consistent
But when you call map.get
the changes are visible, which means the map.get will return null because you asking for a key that doesn't exist
Upvotes: 1
Reputation: 460
Check out the JavaDocs (assuming Java8) for keySet() [https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html#keySet--][1]
Returns a Set view of the keys contained in this map. The set is backed by the map, so changes to the map are reflected in the set, and vice-versa. The set supports element removal, which removes the corresponding mapping from this map, via the Iterator.remove, Set.remove, removeAll, retainAll, and clear operations. It does not support the add or addAll operations.
The view's iterators and spliterators are weakly consistent.
Which links to:
they are guaranteed to traverse elements as they existed upon construction exactly once, and may (but are not guaranteed to) reflect any modifications subsequent to construction.
This is what you're seeing.
The iterator which governs the for loop doesn't guarantee to reflect changes after you constructed the view.
The View is always constructed with the 4 original entries. Now, in the example with "Manish", it just happens that the iterator does reflect the modification, so string never takes Manish as value, and you never do map.get("Manish")
. Alas, with Swati the iterator is not reflecting the modification and it still gives you "Swati" as a second element although the data is always consistent: a map.get("Swati")
does reflect the change, as per the JavaDocs.
I haven't read the code in ConcurrentHashMap.MapEntry
(you should), but the reason why this happens with "Swati" and not "Manish" is very likely the following.
At this point, doing iterator.next() would return current
= "Swati" (evne if the element is gone from the map, which shows with the subsequent map.get()
)
If you delete "Manish" (or "Pujan"), the Iterator is able to update nodes
. But if you delete "Swati" it's too late as current
was already loaded with that key.
Upvotes: 1