线程安全的迭代解释

时间:2017-12-19 06:53:19

标签: java multithreading

我对Collection.synchronizedXXX方法有疑问,他们返回基础集合的同步视图。

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

这究竟意味着什么?

我找到了另一句here

  

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

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

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

2 个答案:

答案 0 :(得分:1)

迭代是一个长期运行的操作。由Collection.synchronizedXXX添加的逻辑会将next()上的每个Iterator电话视为单独的电话,这将是synchronized,但您需要确保在您和{ #39;完全完成迭代。这就是为什么你必须在整个迭代过程中自己添加synchronized块。

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

  

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

答案 1 :(得分:1)

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

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

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