本文介绍了java中的迭代器类型(弱一致)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我理解快速失败(LinkedList)和失败安全(copyonwrite)迭代器,但是弱的一致性仍然是个谜。

I understand fail-fast (LinkedList) and fail-safe (copyonwrite) iterators, however weakly consistent remains a mystery.

文档说它可能反映了基础馆藏的变化,但不能保证。所以我认为弱一致性不会创建后备集合的副本。 (在并发Map中,它在同一个bucketarray上工作)。

Documentation says it might reflect the changes of the underlying collections but there is no guarantee. So I assume that weakly consistent do not create copy of the backing collection. (in a concurrent Map it works on the same bucketarray).

我假设如果一个线程A创建一个迭代器并且经过了一半,那么当线程B放入一个项目时在数组开头的桶中,这个更改对于线程A的迭代器是不可见的。

I assume if a thread A creates an iterator and gone through halfway, when comes thread B that puts an item to the bucket at the beginning of the array that this change wont be visible to the iterator of thread A.

如果B将该项放到数组的末尾,A会看到它。

If B would have put that item to the end of the array, A would have seen it.

是否可能有一个nosuchelement异常?

Is it possibly to have a nosuchelement exception?

如果线程A创建一个迭代器,然后遍历到一个项目X,它有一个下一个项目Y,然后jvm停止线程A并恢复线程B,谁删除Y.这对线程A是可见的(我想是这样否则并发映射将不是线程安全的,但不知道它的迭代器是如何实现的,因为它对于线程A是不可见的,那么它很容易抛出异常。

if thread A creates an iterator, then traverse to an item X which has a next item Y , then jvm stops thread A and resumes thread B, who removes Y. Will this be visible to thread A (I guess so otherwise concurrent map wouldn't be thread safe, but know nothing about how its iterator is implemented), because it is not visible to thread A then it could easily throw an exception.

推荐答案

弱一致的定义在 java.util.concurrent 包文档。为方便起见,我将引用相关位。关于弱一致的迭代器和分裂器,文档说:

The definition of weakly consistent is given in the java.util.concurrent package documentation. For convenience I'll quote the relevant bits. Regarding weakly consistent iterators and spliterators, the documentation says:

这没有说明(以及使用单词时可能隐含的内容)一致的)是迭代不会导致错误,例如 IndexOutOfBoundsException NoSuchElementException 。它也没有说明迭代是否会终止! (我相信它会。)从某种意义上说,这种行为确实是一致的,尽管保证相当薄弱。如果在迭代期间发生修改,第三个子弹特别明确地不保证迭代会看到哪些元素。

What this doesn't say (and what may be implicit in the use of the word "consistent") is that iteration won't result in an error such as IndexOutOfBoundsException or NoSuchElementException. It also doesn't say whether that the iteration will even terminate! (I believe it will.) In some sense this behavior is indeed consistent, though the guarantees are pretty weak. The third bullet in particular explicitly doesn't make any guarantees about what elements are seen by the iteration if modifications occur during iteration.

请考虑以下示例:

    List<String> input = Arrays.asList("a", "b", "c", "d", "e");
    List<String> output = new ArrayList<>();

    Deque<String> deque = new ConcurrentLinkedDeque<>(input);
    for (String s : deque) {
        output.add(s);
        if (s.equals("c")) {
            deque.addFirst("XXX");
            deque.removeLast();
        }
    }

A ConcurrentLinkedDeqeue 是具有弱一致迭代语义的集合的示例。此代码对其进行迭代并将每个元素添加到副本中,但在迭代过程中,deque被修改。

A ConcurrentLinkedDeqeue is an example of a collection with weakly consistent iteration semantics. This code iterates over it and adds each element seen into a copy, but in the middle of the iteration, the deque is modified.

如果您尝试使用 LinkedList 你会得到一个 ConcurrentModificationException 。使用 ConcurrentLinkedDeque ,输出列表是

If you try this with a LinkedList you'll get a ConcurrentModificationException as you expect. With a ConcurrentLinkedDeque, the output list is

    [a, b, c, d]

请注意,在删除e之前添加了XXX,因此输出列表仅反映在迭代期间对输入所做的修改的一些。由于迭代在这种情况下从左向右进行,因此不会看到对当前迭代点左侧进行的修改,并且可以看到对当前迭代点右侧的修改。当然,并非所有集合都有这么简单的迭代顺序。

Note that "XXX" was added before the "e" was removed, so the output list reflects only some of the modifications that were made to the input during the iteration. Since iteration proceeds left-to-right in this case, it's not surprising that modifications made to the left of the current iteration point aren't seen, and modifications made to the right of the current iteration point are seen. Of course, not all collections have such a straightforward iteration order.

另请注意,输出不会反映输入的快照,因为它在任何时间点都会发生。 (如果你想要快照语义,你需要使用像 CopyOnWriteArrayList 这样的东西。)唯一的保证是迭代看到的元素在某些时候出现在输入中。这是一个非常弱的保证!

Note also that the output doesn't reflect a snapshot of the input as it occurred at any point in time. (If you want snapshot semantics, you'd need to use something like CopyOnWriteArrayList.) The only guarantee is that the elements seen by the iteration were present in the input at some point. That's a pretty weak guarantee!

然而,它比我称之为不一致的行为更强大。考虑使用索引(而不是Iterator对象)迭代ArrayList的代码:

It is, however, stronger than what I'd call inconsistent behavior. Consider this code that uses indexes (instead of an Iterator object) to iterate over an ArrayList:

    List<String> input = Arrays.asList("a", "b", "c", "d", "e");
    List<String> output = new ArrayList<>();

    List<String> arrayList = new ArrayList<>(input);
    for (int i = 0; i < arrayList.size(); i++) {
        String s = arrayList.get(i);
        output.add(s);
        if (i == 2) {                   // <<< MODIFY
            arrayList.add(0, "XXX");
        }
    }

在这种情况下,输出为

    [a, b, c, c, d, e]

重复元素c,它只在输入中出现一次。这显然是一个错误。或者,假设标记为MODIFY的行更改为:

which repeats the element "c" which occurs only once in the input. That's clearly an error. Or, suppose the line marked MODIFY is changed to this:

        if (s.equals("c")) {

在这种情况下,循环永远不会终止!您还可以轻松地想象,在索引样式循环中,在正确(错误)时间修改列表将导致 IndexOutOfBoundsException

In this case the loop will never terminate! You can also easily imagine cases where, with an index-style loop, modifying the list at exactly the right (wrong) time will cause an IndexOutOfBoundsException.

因此,您可以看到在修改集合时迭代一个集合可能会出现很多问题。弱一致的迭代提供了对重复元素的保证,以及可能发生的各种错误或无限循环。 弱点是它们几乎不能保证在迭代期间确切观察到哪些元素。

So you can see that there are a lot of things that can go wrong with iterating over a collection while it's being modified. Weakly consistent iteration provides guarantees against repeated elements and against a variety of errors or infinite loops that can occur. The "weakness" is that they provide few guarantees about exactly which elements are observed during iteration.

最后,请注意失败快速弱一致是Java SE规范中定义和使用的特定术语。官方Java文档中的任何地方都不使用术语故障安全。因此,我建议不要使用fail-safe来描述任何Java集合的并发修改策略。有些人认为故障安全与快速失败相反,你会看到这种情况发生在互联网上的各种博客和文章中。坦率地说,我认为应该避免这种草率的写作。

Finally, note that fail-fast and weakly consistent are particular terms that are defined and used in the Java SE specifications. The term "fail-safe" isn't used anywhere in official Java documentation. Therefore, I recommend not using "fail-safe" to describe any of the Java collections' concurrent-modification policies. Some people think that "fail-safe" is the opposite of "fail-fast" and you'll see this occur in various blogs and articles around the internet. Frankly, I think this is sloppy writing that should be avoided.

这篇关于java中的迭代器类型(弱一致)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-02 15:25