Reputation: 5597
In case of following code, run by multiple threads:
private static final Map<String, keyinfo> mapKeys = new ConcurrentHashMap<String, keyinfo>();
private static void purgeOldKeys() {
for (Map.Entry<String, keyinfo> key : mapKeys.entrySet()) {
if(key.getValue().createTime + keyCacheTime < getCurrentDBTime())
mapKeys.remove(key);
}
}
Can I avoid the synchronizer?
Or because removing already removed element, is not defined according to JavaDoc, the synchronizer will be still required?
Upvotes: 2
Views: 7060
Reputation: 77474
In general, when removing from a collection, it is much cleaner (and faster!) to use a full Iterator
API instead of the lazy "foreach" notion.
The iterator.remove();
will not invalidate the iterator; and it knows the position it was at. Use this pattern:
for (Iterator<> iter = map.entrySet().iterator(); iter.hasNext(); ) {
Map.Entry<> entry = iter.next();
if (testRemoval(entry))
iter.remove(); // <----- remove using the iterator position!
}
It's faster because it does not involve searching the object again. It's more robust, because the iterator knows the object has been removed. In many collections, the code you showed above will "fast fail" because of a concurrent modification.
Upvotes: 5
Reputation: 136062
1) This code can't remove anything because there's a bug in it - mapKeys.remove(key);
- key in your code is in fact a Map.Entry. It should be
for (Map.Entry<String, keyinfo> e : map.entrySet()) {
if (e.getValue().createTime + keyCacheTime < getCurrentDBTime())
map.remove(e.getKey());
}
}
2) As for removing entries while iterating over ConcurrentHashMap it is safe, ConcurrentHashMap.entrySet API
The view's iterator is a "weakly consistent" iterator that will never throw ConcurrentModificationException
and this test confirms it
Map<String, String> map = new ConcurrentHashMap<String, String>();
map.put("1", "2");
map.put("2", "2");
map.put("3", "3");
for (String k : map.keySet()) {
map.remove(k);
}
System.out.println(map);
prints
{}
Upvotes: 4