zoukankan      html  css  js  c++  java
  • java ConcurrentModificationException探究

    当集合结构被修改,会抛出Concurrent Modification Exception。 fail-fast会在以下两种情况下抛出ConcurrentModificationException

    (1)单线程环境 集合被创建后,在遍历它的过程中修改了结构。  

      注意 remove()方法会让expectModcount和modcount 相等,所以是不会抛出这个异常。

    (2)多线程环境 当一个线程在遍历这个集合,而另一个线程对这个集合的结构进行了修改。

    如下:

    private static void test0() {
    
            List<String> list = new ArrayList<>();
            list.add("a1");
            list.add("a2");
            list.add("a3");
            list.add("a4");
            list.add("a5");
            list.add("a6");
            list.add("a7");
            list.add("a8");
    
            for (String s : list) {
                list.remove(s);
            }
    
            System.out.println(list);
    
        }

    运行会抛出异常

    java.util.ConcurrentModificationException

    如果又想在遍历的时候做删除操作呢? 借肋iterator,如下:

    private static void test1() {
    
            List<String> list = new ArrayList<>();
            list.add("a1");
            list.add("a2");
            list.add("a3");
            list.add("a4");
            list.add("a5");
            list.add("a6");
            list.add("a7");
            list.add("a8");
    
            Iterator<String> iter = list.iterator();
            while (iter.hasNext()) {
                String str = iter.next();
                System.out.println(str);
    
                //iter.remove();
                if (Randoms.random(1, 9) % 2 == 0) {
                    iter.remove();
                }
            }
    
            System.out.println(list);
    
        }

    这里我们并没有用list.remove元素而是iter.reomve,但实际list中的元素已经被删除也没有抛异常,为什么会这样?

    调试的时候我们发现iter.reomve执行最终调用的是 ArrayList

    public E remove(int index)

    所以自然影响了原来的集合。

    Iterator被创建之后会建立一个指向原来对象的单链索引表, 当list删除元素里不会影响索引,Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。

    我们再看段代码:

    private static void test2() {
     List list2 = Arrays.asList(new String[]{"a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8",});
    
    Iterator iter2 = list2.iterator(); 
    
    while (iter2.hasNext()) { 
          String str = iter2.next(); System.out.println(str);
    
            //iter.remove();
            if (Randoms.random(1, 9) % 2 == 0) {
                iter2.remove();
            }
        }
    
        System.out.println(list2);
    }

    结果:

    会抛出异常java.lang.UnsupportedOperationException

    为什么呢?感觉跟test1是一样的?

    我们查看源码Arrays:

    public static <T> List<T> asList(T... a) {
            return new ArrayList<>(a);
        }
    
        /**
         * @serial include
         */
        private static class ArrayList<E> extends AbstractList<E>
            implements RandomAccess, java.io.Serializable{...}

    发现两个ArrayList并不是同一个类却取了同一个名字:

    java.util.Arrays.ArrayList!=java.util.ArrayList

    你还是你同一个名字却是另一个他....

    java.util.Arrays.ArrayList并没有实现remove方法,所以也就抛出了UnsupportedOperationException 就不足为其了!

    看似简单的问题多想一点就好了!

  • 相关阅读:
    UIButton中setTitleEdgeInsets和setImageEdgeInsets的使用
    关于自定义导航条UIBarButtonItem偏移的问题
    iOS端使用二维码扫描(ZBarSDK)和生成(libqrencode)功能
    CocoaPods安装和使用教程
    IOS中NSUserDefaults的用法(轻量级本地数据存储) (转)
    UIPickerView简单选择器的基本使用
    [原]Unity手游之路&lt;三&gt; 基于Unity+Java的聊天室源码
    [原]UML建模语言进阶
    [原]Java多线程编程学习笔记之九:使用wait/notify/notifyAll实现线程间通信的几点说明
    [原]MySQL的表分区
  • 原文地址:https://www.cnblogs.com/tankaixiong/p/6007093.html
Copyright © 2011-2022 走看看