I am trying to remove certain entries from a ConcurrentHashMap
. However since this happens in a multithreaded environment, entries may be removed and/or modified while the iteration is in progress. When this happens the remove
method on the iterator will remove the entry even if it was modified since received through next
. I have constructed an example program to illustrate this:
ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();
map.put("foo", "bar");
map.put("quz", "qaz");
CountDownLatch foundBar = new CountDownLatch(1);
CountDownLatch doneModifying = new CountDownLatch(1);
CountDownLatch doneIterating = new CountDownLatch(1);
new Thread(() -> {
try {
Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, String> entry = it.next();
if (entry.getValue().equals("bar")) {
foundBar.countDown();
doneModifying.await();
it.remove();
}
}
doneIterating.countDown();
} catch (InterruptedException e) {
throw new Error(e);
}
}).start();
foundBar.await();
map.put("foo", "nob");
doneModifying.countDown();
doneIterating.await();
System.out.println(map);
The output will be {quz=qaz}
and not as I expected {quz=qaz,foo=nob}
. My question is: How do I achieve the desired behavior? Is the remove(key, value)
method on the Map during the iteration the right choice?
Yes, you should use the two argument remove
method. While direct collection mutation during iteration is generally a bad thing for most java collections, ConcurrentHashMap allows this.