问题
Is using the remove() method okay? I've read an article that synchronization hasn't been added to the remove method. How do I properly remove a specific item from a ConcurrentHashMap?
Example Code:
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);
}
回答1:
The remove
method does synchronize on a lock. Indeed checking the code of ConcurrentHashMap#remove()
, there is a call to a lock
method that acquires the lock:
public V remove(Object key) {
int hash = hash(key.hashCode());
return segmentFor(hash).remove(key, hash, null);
}
where ConcurrentHashMap.Segment#remove(key, hash, null)
is defined as:
V remove(Object key, int hash, Object value) {
lock();
try {
...
Note the Javadoc description:
Retrieval operations (including
get
) generally do not block, so may overlap with update operations (includingput
andremove
). Retrievals reflect the results of the most recently completed update operations holding upon their onset. For aggregate operations such asputAll
andclear
, 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 throwConcurrentModificationException
. However, iterators are designed to be used by only one thread at a time.
回答2:
An Iterator should do the job:
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();
}
}
Reference: https://dzone.com/articles/removing-entries-hashmap
回答3:
You can use directly removeIf on the entrySet :
map.entrySet().removeIf( entry -> .. some condicion on entry )
Pay attention there is a bug in Java 8 that is only fixed from Java 9 ( here ).
来源:https://stackoverflow.com/questions/27867990/java-remove-specific-item-from-concurrenthashmap