【问题标题】:Concurrent Hashmap - Fail safe issue并发 Hashmap - 故障安全问题
【发布时间】:2014-09-05 15:10:20
【问题描述】:

我正在尝试使用 ConcurrentHashMap 的故障安全示例。

下面是我试过的示例 sn-p..

ConcurrentHashMap<String, String> cMap = new ConcurrentHashMap<String, String>();
cMap.put("1", "Windows Phone");
cMap.put("2", "iPhone");
cMap.put("3", "HTC");

Iterator iterator=cMap.keySet().iterator();

while (iterator.hasNext()) {
    System.out.println(cMap.get(iterator.next()));
    cMap.put("Samsung", "S5");
}

输出是:

Windows Phone
HTC
iPhone

这是一个我理解的故障安全示例。

但是当我尝试下面的示例时,我得到了不同的输出。

ConcurrentHashMap<String, String> cMap = new ConcurrentHashMap<String, String>();
cMap.put("1", "Windows Phone");
cMap.put("2", "iPhone");
cMap.put("3", "HTC");

Iterator iterator=cMap.keySet().iterator();

while (iterator.hasNext()) {
    System.out.println(cMap.get(iterator.next()));
    cMap.put("4", "S5");
}

输出是

Windows Phone
HTC
S5
iPhone

上面两个代码sn-ps有什么区别。在第二个代码 sn-p 中,我添加了 cMap.put("4", "S5"); 并且正在添加。但在第一个 sn-p 中,我添加了未添加到 ConcurrentHashmap 的 cMap.put("Samsung", "S5");。我是否犯了任何错误或其他可能是导致这种不同输出的原因。

提前致谢。

【问题讨论】:

  • 您尝试运行代码多少次?输出的差异总是存在吗?
  • 很多次@SimoneGianni。但是我得到了同样的输出。
  • 如果以下两个答案之一满足您的问题,请接受。

标签: java hashmap concurrenthashmap concurrentmodification


【解决方案1】:

与非并发 hashmap 相比,并发映射不会快速失败,如果您在迭代时添加内容。

但是,不能保证迭代器(或 get() 方法,或任何其他读取操作)何时以及是否会看到新添加/删除的元素。

来自文档:

迭代器和枚举返回反映哈希表在创建迭代器/枚举时或之后的某个时间点的状态的元素

编辑:

一致的不同结果背后的原因在于 ConcurrentHashMap 如何组织段并对其进行迭代。

根据键的哈希值将键映射到不同的段:

“1”-> 15 “2”-> 0 “3”-> 6 “4”-> 5 “三星”-> 7

当调用迭代器时,它会从最后一个到第一个对段进行迭代。

因此,在 0 时刻,迭代器从第 15 段开始,在那里它找到键“1”=“Windows phone”,它首先进入输出。

然后,由于迭代器内部实现,它到达下一个元素,即第 6 段的 "3"="HTC"。

此时“S5”的插入就位。如果键为“4”,则进入第 5 段,如果键为“Samsung”,则进入第 7 段。

发送“HTC”到输出后,它会搜索下一个元素。

当key为“4”时,进入第5段,找到“4”="S5",发送到输出。

当key为“Samsung”时,入口进入第7段,该段已经被迭代器扫描发现为空,所以没有找到,直接进入第0段取回“2”=“Iphone” .

这解释了行为。

【讨论】:

  • 是的,即使我以前读过这个文件。 Segmentation 的概念正在 ConcurrentHashMap 中使用,其中并非所有内容都被锁定。只有其中的一部分被锁定。这是造成这种不同输出的原因吗....????
  • ConcurrentHashMaps 不使用锁定。不知道你所说的分段是什么意思。
  • @Kaushi 是的,这是因为分段,我添加了一个解释内部结构的编辑
  • 感谢@SimoneGianni...从您的解释中了解了这一点。
【解决方案2】:

但是在第一个 sn-p 中,我添加了 cMap.put("Samsung", "S5");它没有被添加到 ConcurrentHashmap 中。

这是不正确的。您正在将其添加到哈希映射中。之后打印出来,你会看到条目在那里。

但是,您在迭代哈希映射时添加到哈希映射的项目可能会或可能不会被当前迭代器迭代。您的两个样本都表现出这两种行为。

java.util.concurrent 包中的结构在迭代时没有检查修改(您称之为“故障安全”),因为它们的全部意义在于同时使用。甚至不能保证常规容器。

【讨论】:

  • 正在添加到 ConcurrentHashmap。是的,当我之后打印它时,它正在被打印。两个 sn-ps 在代码方面都是相同的,只是在迭代时传递的 KEYS 和 VALUES 不同。因为这个输出不同......?????这是我的疑问。
【解决方案3】:

两个并行线程同时写入 ConcurrentHashMap。按照 ConcurrentHashMap 的默认实现,最多 16 个线程可以并行读写。但最坏的情况是,如果两个对象位于 ConcurrentHashMap 的同一段或分区中,则无法并行写入。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-03
    相关资源
    最近更新 更多