简体   繁体   English

为什么Vector方法Iterator和ListIterator快速失败

[英]why Vector methods Iterator and ListIterator are fail fast

According to http://download.oracle.com/javase/1.4.2/docs/api/java/util/Vector.html 根据http://download.oracle.com/javase/1.4.2/docs/api/java/util/Vector.html

The Iterators returned by Vector's iterator and listIterator methods are fail-fast: if the Vector is structurally modified at any time after the Iterator is created, in any way except through the Iterator's own remove or add methods, the Iterator will throw a ConcurrentModificationException. Vector的iterator和listIterator方法返回的迭代器是快速失败的:如果在创建Iterator之后的任何时候对Vector进行结构修改,除了通过Iterator自己的remove或add方法之外,Iterator将抛出ConcurrentModificationException。 Thus, in the face of concurrent modification, the Iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future. 因此,在并发修改的情况下,迭代器快速而干净地失败,而不是在未来的未确定时间冒任意,非确定性行为的风险。 The Enumerations returned by Vector's elements method are not fail-fast. Vector的元素方法返回的枚举不是快速失败的。 Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. 请注意,迭代器的故障快速行为无法得到保证,因为一般来说,在存在不同步的并发修改时,不可能做出任何硬性保证。 Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. 失败快速迭代器会尽最大努力抛出ConcurrentModificationException。 Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs 因此,编写依赖于此异常的程序以确保其正确性是错误的:迭代器的快速失败行为应仅用于检测错误

Could you give me an example to validate the above set of statements ?Im still unclear with fail fast behaviour of vector's method Iterator and ListIterator.? 你能给我一个例子来验证上面的语句吗?我还不清楚向量的方法Iterator和ListIterator的失败快速行为。 Confused :-(( 困惑: - ((

if the Vector is structurally modified at any time after the Iterator is created, in any way except through the Iterator's own remove or add methods, the Iterator will throw a ConcurrentModificationException . 如果在创建Iterator之后的任何时候对Vector进行结构修改,除了通过Iterator自己的remove或add方法之外,Iterator将抛出ConcurrentModificationException

Here is an example: 这是一个例子:

import java.util.*;

public class Test {

    public static void main(String[] args) {
        List<String> strings = new Vector<String>();

        strings.add("lorem");
        strings.add("ipsum");
        strings.add("dolor");
        strings.add("sit");

        int i = 0;

        Iterator<String> iter = strings.iterator();
        while (iter.hasNext()) {
            System.out.println(iter.next());

            // Modify the list in the middle of iteration.
            if (i++ == 1)
                strings.remove(0);
        }
    }
}

Output: 输出:

lorem
ipsum
Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
    at java.util.AbstractList$Itr.next(AbstractList.java:343)
    at Test.main(Test.java:18)

The program does the following: 该计划执行以下操作:

  1. Creates a Vector and gets an iterator 创建一个Vector并获取一个迭代器
  2. Calls next() twice. 调用next()两次。
  3. Modifies the vector (by removing the first element) 修改向量(通过删除第一个元素)
  4. Calls next() again (after the vector has been modified) 再次调用next() (在向量被修改之后)
  5. This causes a ConcurrentModificationException to be thrown. 这会导致抛出ConcurrentModificationException

Since Java's for-each loops rely on iterators these constructs may also throw ConcurrentModificationExceptions. 由于Java的for-each循环依赖于迭代器,因此这些构造也可能抛出ConcurrentModificationExceptions。 The solution is to make a copy of the list before iterating (so you iterate over a copy) or to use for instance an CopyOnWriteArrayList like this: 解决方案是在迭代之前制作列表的副本(所以你迭代一个副本)或者使用像这样的CopyOnWriteArrayList

import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

public class Test {

    public static void main(String[] args) {
        List<String> strings = new CopyOnWriteArrayList<String>();

        strings.add("lorem");
        strings.add("ipsum");
        strings.add("dolor");
        strings.add("sit");

        int i = 0;

        Iterator<String> iter = strings.iterator();
        while (iter.hasNext()) {
            System.out.println(iter.next());

            // Modify the list in the middle of iteration.
            if (i++ == 1)
                strings.remove(0);
        }
    }
}

Output: 输出:

lorem
ipsum
dolor
sit

A simple way to trigger a concurrent modification exception is 触发并发修改异常的一种简单方法是

List<String> strings = new ArrayList<String>();
strings.add("a");
strings.add("b");
for(String s: strings)
  strings.remove(s);

This triggers an exception because the collection is changed while iteration over the collection. 这会触发异常,因为在对集合进行迭代时会更改集合。

The reason the Iterator fails fast is to help you detect that a collection was modified concurrently (which these collections don't support) and help detect where the error occurred. Iterator快速失败的原因是帮助您检测集合是否同时被修改(这些集合不支持)并帮助检测错误发生的位置。 If it didn't have this feature you could have subtle bugs which may not show a problem until much later in your code. 如果它没有此功能,您可能会遇到一些细微的错误,这些错误可能会在您的代码中稍后出现问题。 (Making them much harder to race) (让他们更难参加比赛)

The newer concurrency collections handle concurrent modification differently and don't do this in general. 较新的并发集合以不同方式处理并发修改,并且通常不执行此操作。 They were introduced into core Java in 2004, i suggest you have a look at these newer collections. 他们在2004年被引入核心Java,我建议你看看这些新的集合。

BTW: Don't use Vector unless you have to. 顺便说一句:除非必须,否则不要使用Vector。

Say you have a Vector of Integers containing 1-10 and you want to remove the odd numbers. 假设您有一个包含1-10的整数向量,并且您想要删除奇数。 You iterate over this list looking for odds and using the Iterators remove() method. 您遍历此列表以查找赔率并使用Iterators remove()方法。 After this you have some code that of course assumes there are no odd numbers in the Vector. 在此之后你有一些代码,当然假设Vector中没有奇数。 If another thread modifies the vector during this process, there might sometimes actually be an odd number (depending on the race condition), breaking the code that comes after. 如果另一个线程在此过程中修改了向量,有时可能实际上存在奇数(取决于竞争条件),从而破坏了之后的代码。 Perhaps it doesn't even break right away; 也许它甚至没有立即破裂; maybe it doesn't cause a problem until hours or days later -- very hard to troubleshoot. 也许它不会在几小时或几天后引起问题 - 很难排除故障。 This is what happens with the elements() method. 这就是elements()方法所发生的情况。

Fail-fast means trying to detect this (potential) problem as soon as it occurs and sounding the alarm, which makes it much easier to troubleshoot. 快速失败意味着一旦发生并发出警报就会尝试检测此(潜在)问题,这样可以更容易地进行故障排除。 As soon as another thread is found to have modified the collection, an exception is thrown. 一旦发现另一个线程修改了集合,就会抛出异常。 This is what happens with the iterators. 这是迭代器发生的事情。

The Iterators returned by iterator() and listIterator() actively watch for unexpected modifications to the underlying list. 迭代iterator()listIterator()返回的iterator()主动监视对基础列表的意外修改。 The Vector class (actually its parent AbstractList), increments a counter each time it is modified. Vector类(实际上是它的父AbstractList)在每次修改时递增一个计数器。 When iterators for the Vector are created, they store a copy of the Vector's modification counter. 当创建Vector的迭代器时,它们存储Vector的修改计数器的副本。 Each time you call next() or remove() the Iterator compares it's stored value for the counter to the Vector's actual counter. 每次调用next()remove() ,Iterator都会将计数器的存储值与Vector的实际计数器进行比较。 If they differ, it throws a ConcurrentModificationException. 如果它们不同,则会抛出ConcurrentModificationException。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM