【问题标题】:Why there is difference in output by just changing the key values in ConcurrentHashMap为什么仅通过更改 ConcurrentHashMap 中的键值来输出差异
【发布时间】:2018-10-26 14:01:15
【问题描述】:

如果您看到这张图片,您会发现我刚刚更改了按键,并且令人惊讶地发现了两个不同的结果。在左侧,我发现四个字符串作为输出,而在右侧只有三个字符串作为输出。谁能让我理解这个区别。

【问题讨论】:

  • 将代码、输出和/或可能的错误消息显示为问题中格式正确的文本,而不是图像或外部链接。

标签: java collections iterator concurrenthashmap


【解决方案1】:

ConcurrentHashMap.iterator() 不保证您在迭代时会看到或不会看到添加的条目。它有一个内部顺序传递条目,如果您在该点之前添加,则取决于您将看不到条目。

如果您再次遍历这些值,您应该会在第二个中看到它在第一个条目之前。

【讨论】:

    【解决方案2】:

    您使用ConsurrentHashMap 而不是像HashMap 这样的常规Map 实现可能是有原因的。如果您尝试使用其中一种实现并运行您的代码,您会注意到ConcurrentModificationException,每当您在迭代它时更新HashMap 时都会抛出它。如果您将该实现更改为ConcurrentHashMap,这将更改以下内容:

    支持检索的完全并发和更新的高预期并发的哈希表。 [...] 检索操作(包括 get)通常不会阻塞,因此可能与更新操作(包括 put 和 remove)重叠。检索反映了最近完成的更新操作在开始时保持的结果。

    因此,在您迭代 Map 时允许并发更新。现在,您是否可以实际看到该值的问题可能与 Map 实现的迭代顺序有关(它可以在 Java 版本之间更改,因为 通常Map)。如果元素是在当前迭代之前插入的,它将不会被迭代。如果元素是在之后插入的,它会在控制台上打印出来。毕竟,你不应该依赖它。

    但是,如果您再次遍历 Map

    Iterator<String> it = map.keySet().iterator();
    while (it.hasNext()) {
        System.out.println(map.get(it.next()));
    }
    

    您将正确地看到输出中的值:

    iPhone
    HTC one
    S5
    Xperia Z <<< here it is
    iPhone
    HTC one
    S5
    

    现在可以证明之前的假设是正确的,因为密钥“Sony”已经被首先迭代,所以它不会出现在之前的迭代中。如果您将此与第一次尝试进行比较,则键“d”已被最后一次迭代,因此它显示在控制台上。确切地说,如果您有一个被迭代的值而不是第一个值,它将显示出来(因为您已经在第二次迭代时添加了它)。

    但是,如前所述,请记住,Java 版本之间的迭代顺序可能会发生变化,这可能只适用于您的具体示例。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-10-16
      • 2019-10-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多