Java ConcurrentHashMap and for each loop

Java ConcurrentHashMap and for each loop

假设我有以下 ConcurrentHashMap:

ConcurrentHashMap<Integer,String> identificationDocuments = new ConcurrentHashMap<Integer,String>();
        
identificationDocuments.put(1, "Passport");
identificationDocuments.put(2, "Driver's Licence");

我如何使用 for each 循环安全地遍历地图并将每个条目的值附加到字符串?

我不知道您是否真的在问这个问题,但是要遍历任何地图,您需要遍历 keySet()

StringBuffer result = new StringBuffer("");

for(Integer i: indentificationDocuments.keySet()){
        result.append(indentificationDocuments.get(i));
}

return result.toString();

ConcurrentHashMap 产生的迭代器是 weakly consistent。即:

  • they may proceed concurrently with other operations
  • they will never throw ConcurrentModificationException
  • they are guaranteed to traverse elements as they existed upon construction exactly once, and may (but are not guaranteed to) reflect any modifications subsequent to construction.

最后一个要点非常重要,一个迭代器 returns 自迭代器创建以来某个时刻的地图视图,引用 javadocs for ConcurrentHashMap 的不同部分:

Similarly, Iterators, Spliterators and Enumerations return elements reflecting the state of the hash table at some point at or since the creation of the iterator/enumeration.

所以当你像下面这样循环键集时,你需要仔细检查该项目是否仍然存在于集合中:

for(Integer i: indentificationDocuments.keySet()){
    // Below line could be a problem, get(i) may not exist anymore but may still be in view of the iterator
    // someStringBuilder.append(indentificationDocuments.get(i));
    // Next line would work
    someStringBuilder.append(identificationDocuments.getOrDefault(i, ""));
}

将所有字符串附加到 StringBuilder 本身的行为是安全的,只要您在一个线程上执行此操作或以线程安全的方式完全封装 StringBuilder