线程安全的迭代解释

问题描述 投票:1回答:2

我有一个关于Collection.synchronizedXXX方法的问题,他们返回底层集合的同步视图。

使用这些,我们必须手动同步迭代(例如here),否则可能导致非确定性行为。

它到底意味着什么?

我发现了另一句话here

面对并发访问,用户必须在迭代时手动同步返回的集合。原因是迭代是通过对集合的多次调用来完成的,集合必须组成一个单独的原子操作。

这就是我被困住的地方。我想如果我想修改这个系列,我会得到一个ConcurrentModificationException。所以我需要进行同步以避免出现此异常(例如,由于编译器完成上下文切换,迭代被“暂停”)。

第二个环节有希望证实我的想法。 “非确定性行为”句子怎么样?它是否反映了相同的想法(迭代暂停)或幕后有什么新东西?

java multithreading
2个回答
1
投票

迭代是一个长期运行的操作。 Collection.synchronizedXXX添加的逻辑将看到每个next()调用Iterator作为单独的调用,这将是synchronized,但是你需要确保在完成迭代之前不会修改集合。这就是为什么你必须在整个迭代过程中自己添加synchronized块的原因。

ConcurrentModificationException,例如由ArrayList抛出,不保证会抛出:

请注意,迭代器的快速失败行为无法得到保证,因为一般来说,在存在不同步的并发修改时,不可能做出任何硬性保证。失败快速的迭代器会尽最大努力抛出ConcurrentModificationException。因此,编写依赖于此异常的程序以确保其正确性是错误的:迭代器的快速失败行为应该仅用于检测错误。


1
投票

迭代包括执行以下操作(直接或间接使用foreach循环):

while (iterator.hasNext()) {
    iterator.next();
}

因此,如果在调用hasNext()和调用next()之间存在上下文切换,而另一个线程从集合中删除元素,则最终会出现不可预测的行为:迭代器告诉您有下一个元素,实际上并没有。您不是在列表的一致快照上进行迭代,而是在移动目标上进行迭代,并且在线程之间不共享的列表上永远不会发生异常。

© www.soinside.com 2019 - 2024. All rights reserved.