当前位置:  首页>> 技术小册>> Java语言基础10-Java中的集合

  • 异常的产生原因:在迭代器遍历集合的过程中,调用集合自身的功能(例如:调用集合的 add 和 remove 方法),改变集合的长度。

  • 示例:并发修改异常

  1. package com.github.collection1.demo4;
  2. import java.util.ArrayList;
  3. import java.util.Collection;
  4. import java.util.Iterator;
  5. /**
  6. * @author maxiaoke.com
  7. * @version 1.0
  8. */
  9. public class Test {
  10. public static void main(String[] args) {
  11. Collection<String> collection = new ArrayList<>();
  12. collection.add("aa");
  13. collection.add("bb");
  14. collection.add("cc");
  15. collection.add("dd");
  16. for (Iterator<String> iterator = collection.iterator(); iterator.hasNext();) {
  17. String ele = iterator.next();
  18. System.out.println("ele = " + ele);
  19. collection.add("ee");
  20. }
  21. }
  22. }

  • 如果在 Iterator、ListIterator 迭代器创建后的任意时间从结构上修改了集合(通过迭代器自身的remove或add方法之外的任何其他方式),则迭代器会抛出 ConcurrentModificationException 异常。因此,面对并发的修改,迭代器很快会失败,而不是冒着在将来不确定的时间发生不确定行为的风险。
  • 这样设计时因此,迭代器代表集合中的某个元素的位置,内部会存储某些能够代表该位置的信息。当集合发生改变的时候,该信息的含义可能会发生变化,这个时候操作迭代器就有可能造成不可预料的后果。因此,果断抛出异常阻止,是最好的方法,者就是 Iterator 迭代器的快速失败机制。
  • 需要注意的是,迭代器的快速失败机制行文不能得到保证,一般来说,存在不同步的并发修改时,不可能做出任何坚决的保证。快速失败机制尽最大努力抛出 ConcurrentModificationException 。因此,迭代器的快速失败行文应该仅仅用于检测bug 。

  • 快速失败机制的实现原理:
    ○ ① 在 ArrayList 等集合类中都有一个 modCount 变量,它用来记录集合的结构被修改的次数。
    ○ ② 当我们给集合添加或删除元素的时候,会导致 modCount++ 。
    ○ ③ 当我们使用 Iterator 迭代器遍历集合的时候,会使用一个变量记录当前集合的 modCount 。例如:int expectedModCount = modCount;,并且,在迭代器每次 next() 迭代元素的时候,都要检查 expectedModCount != modCount ,如果不相等,则说明调用了 Iterator 迭代器以外的 Collection 的 add 、remove 等方法,修改了集合的结构,使得 modCount++ ,值变了,就会抛出 ConcurrentModificationException 。


该分类下的相关小册推荐: