Java 从 ConcurrentHashMap 中删除特定项

Java Remove Specific Item From ConcurrentHashMap

使用remove()方法可以吗?我读过一篇文章说同步没有被添加到 remove 方法中。如何从 ConcurrentHashMap 中正确删除 specific 项?

示例代码:

    ConcurrentHashMap<String,Integer> storage = new ConcurrentHashMap<String,Integer>();
    storage.put("First", 1);
    storage.put("Second", 2);
    storage.put("Third",3);


    //Is this the proper way of removing a specific item from a tread-safe collection?
    storage.remove("First");

    for (Entry<String, Integer> entry : storage.entrySet()) {
        String key = entry.getKey();
        Object value = entry.getValue();
        // ...
        System.out.println(key + " " + value);
    }

remove 方法在锁上进行同步。确实检查了 ConcurrentHashMap#remove() 的代码,有一个调用 lock 获取锁的方法:

public V remove(Object key) {
    int hash = hash(key.hashCode());
    return segmentFor(hash).remove(key, hash, null);
}

其中 ConcurrentHashMap.Segment#remove(key, hash, null) 定义为:

V remove(Object key, int hash, Object value) {
     lock();
     try {
        ...

注意 Javadoc 描述:

Retrieval operations (including get) generally do not block, so may overlap with update operations (including put and remove). Retrievals reflect the results of the most recently completed update operations holding upon their onset. For aggregate operations such as putAll and clear, concurrent retrievals may reflect insertion or removal of only some entries. Similarly, Iterators and Enumerations return elements reflecting the state of the hash table at some point at or since the creation of the iterator/enumeration. They do not throw ConcurrentModificationException. However, iterators are designed to be used by only one thread at a time.

一个Iterator应该做的工作:

Iterator<Map.Entry<String, Integer>> iterator = storage.entrySet().iterator();
while(iterator.hasNext())
{
    Map.Entry<String, Integer> entry = iterator.next();
    if(entry.getKey().equals("First"))
    {
       iterator.remove();
    }
 }

参考:https://dzone.com/articles/removing-entries-hashmap

您可以直接在 entrySet 上使用 removeIf :

map.entrySet().removeIf( entry -> .. some condicion on entry ) 

注意 Java 8 中有一个 bug 仅从 Java 9 修复( here ).