【问题标题】:Java ConcurrentHashMap and for each loopJava ConcurrentHashMap 和每个循环
【发布时间】:2015-07-07 17:17:18
【问题描述】:

假设我有以下ConcurrentHashMap

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

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

【问题讨论】:

  • 你说的安全是什么意思?
  • @sstan - 如何正确迭代线程安全集合?我看过带有while循环的例子,但是我想要一个for循环,你怎么做?

标签: java thread-safety


【解决方案1】:

ConcurrentHashMap 生成的迭代器是weakly consistent。那就是:

  • 它们可能与其他操作同时进行
  • 他们永远不会抛出 ConcurrentModificationException
  • 保证它们只遍历构建时存在的元素一次,并且可能(但不保证)反映构建后的任何修改。

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

类似地,迭代器、拆分器和枚举返回的元素反映哈希表在创建迭代器/枚举时或之后的某个时间点的状态。

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

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

【讨论】:

    【解决方案2】:

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

    StringBuffer result = new StringBuffer("");
    
    for(Integer i: indentificationDocuments.keySet()){
            result.append(indentificationDocuments.get(i));
    }
    
    return result.toString();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-09-03
      • 2013-10-30
      • 2014-05-04
      • 1970-01-01
      • 2015-10-06
      • 2012-12-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多