我有一个关于Collection.synchronizedXXX
方法的问题,他们返回底层集合的同步视图。
使用这些,我们必须手动同步迭代(例如here),否则可能导致非确定性行为。
它到底意味着什么?
我发现了另一句话here:
面对并发访问,用户必须在迭代时手动同步返回的集合。原因是迭代是通过对集合的多次调用来完成的,集合必须组成一个单独的原子操作。
这就是我被困住的地方。我想如果我想修改这个系列,我会得到一个ConcurrentModificationException
。所以我需要进行同步以避免出现此异常(例如,由于编译器完成上下文切换,迭代被“暂停”)。
第二个环节有希望证实我的想法。 “非确定性行为”句子怎么样?它是否反映了相同的想法(迭代暂停)或幕后有什么新东西?
迭代是一个长期运行的操作。 Collection.synchronizedXXX
添加的逻辑将看到每个next()
调用Iterator
作为单独的调用,这将是synchronized
,但是你需要确保在完成迭代之前不会修改集合。这就是为什么你必须在整个迭代过程中自己添加synchronized
块的原因。
ConcurrentModificationException
,例如由ArrayList
抛出,不保证会抛出:
请注意,迭代器的快速失败行为无法得到保证,因为一般来说,在存在不同步的并发修改时,不可能做出任何硬性保证。失败快速的迭代器会尽最大努力抛出
ConcurrentModificationException
。因此,编写依赖于此异常的程序以确保其正确性是错误的:迭代器的快速失败行为应该仅用于检测错误。
迭代包括执行以下操作(直接或间接使用foreach循环):
while (iterator.hasNext()) {
iterator.next();
}
因此,如果在调用hasNext()和调用next()之间存在上下文切换,而另一个线程从集合中删除元素,则最终会出现不可预测的行为:迭代器告诉您有下一个元素,实际上并没有。您不是在列表的一致快照上进行迭代,而是在移动目标上进行迭代,并且在线程之间不共享的列表上永远不会发生异常。