删除已删除的ConcurrentHashMap元素有多安全?

时间:2013-01-29 14:58:49

标签: java multithreading synchronization concurrenthashmap

如果是以下代码,请由多个线程运行:

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);
    }
}

我可以避开同步器吗?

或者因为删除已经删除的元素,没有根据JavaDoc定义,仍然需要同步器?

2 个答案:

答案 0 :(得分:5)

通常,当从集合中删除时,使用完整的Iterator API而不是懒惰的“foreach”概念会更清晰(也更快!)。

iterator.remove();不会使迭代器失效;它知道它的位置。使用这种模式:

for (Iterator<> iter = map.entrySet().iterator(); iter.hasNext(); ) {
    Map.Entry<> entry = iter.next();
    if (testRemoval(entry))
        iter.remove(); // <----- remove using the iterator position!
}

它更快,因为它不再涉及搜索对象。它更健壮,因为迭代器知道对象已被删除。在许多集合中,由于并发修改,上面显示的代码将“快速失败”。

答案 1 :(得分:4)

1)此代码无法删除任何内容,因为其中存在错误 - mapKeys.remove(key); - 代码中的键实际上是Map.Entry。它应该是

for (Map.Entry<String, keyinfo> e : map.entrySet()) {
    if (e.getValue().createTime + keyCacheTime < getCurrentDBTime())
            map.remove(e.getKey());
    }
}

2)至于在ConcurrentHashMap上迭代时删除条目是安全的,ConcurrentHashMap.entrySet API

The view's iterator is a "weakly consistent" iterator that will never throw ConcurrentModificationException

并且此测试证实了它

    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);

打印

{}