为什么仅通过更改ConcurrentHashMap中的键值来在输出上有所不同

时间:2018-10-26 14:01:16

标签: java collections iterator concurrenthashmap

enter image description here

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

2 个答案:

答案 0 :(得分:0)

ConcurrentHashMap.iterator()不保证您迭代时会或不会看到添加的条目。有一个内部订单,它会跳过条目,如果在该点之前添加,则看不到该条目。

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

答案 1 :(得分:0)

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

  

一个哈希表,它支持检索的完全并发性和更新的高期望并发性。 [...]检索操作(包括get)通常不会阻塞,因此可能与更新操作(包括put和remove)重叠。检索反映了发生后最新完成的更新操作的结果。

因此,在迭代Map时允许并发更新。现在,您是否可以实际看到该值的问题与Map实现的迭代顺序有关(该实现可以在Java版本之间更改,因为通常没有迭代顺序)在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

您将在输出中正确看到该值:

double 24.9

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

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