美文网首页程序员
谈一谈ConcurrentModificationExcepti

谈一谈ConcurrentModificationExcepti

作者: jsbintask | 来源:发表于2019-04-09 22:53 被阅读0次
    ConcurrentModificationException

    本文原创地址,我的博客https://jsbintask.cn/2019/04/09/jdk/jdk8-concurrentmodificationexception/(食用效果最佳),转载请注明出处!

    前言

    ConCurrentModificationException是jdk用于限制并发情况下容器结构改变的异常类。当一个线程操作一个容器时,此时如果有另一个线程修改了容器大小,将抛出这个异常,我们看下面两段代码

    ConcurrentModificationException
    ConcurrentModificationException
    Code 2::
    ConcurrentModificationException
    说明:一个线程进行list的排序操作,一个线程移除list中的元素,结果:
    ConcurrentModificationException
    上面代码说明不管是单线程情况下还是多线程并发运行模式下,一旦在某些情况下(如上面的遍历,排序),容器的结构一旦被修改就将抛出ConCurrentModificationException

    源码解析

    为什么会这样呢,这样是不是就代表这些容器是线程安全的呢? 我们通过源码来讨论一下。
    首先第一个例子,一个线程进行遍历操作:for(T t: Collections),通过查看字节码知道,它其实就是使用了Iterator进行了遍历操作:

    ConcurrentModificationException
    接着查看ArrayList中的Iterator发现它内部是这么定义的:
    ConcurrentModificationException
    ArrayList内部有一个modCount成员变量,每次就行修改操作如增加,删除等会增加该值:
    ConcurrentModificationException
    而当初始化一个Iterator时,会记录当前的modCount,以后每次操作(next(), remove())都会检查该值:
    ConcurrentModificationException
    一旦和记录的初始值不相等,则会抛出异常!
    同理,上面的排序操作sort()方法同样是这么定义的:
    ConcurrentModificationException

    这样我们上面的疑问就解开了,之所以会抛出异常,是因为容器内部维护了一个变量modCount,在进行某些操作时(iterator,sort)时,会记录当时的这个值,在操作过程中这个值一旦发生改变则会抛出ConcurrentModificationException。

    jdk中,这种行为被称为快速失败,它的目的是为了尽最大努力的检测线程安全!但是! 它并不能保证容器的线程安全

    ConcurrentModificationException
    这个例子中,我们使用多线程添加了10000个元素,最后成功添加的却只有9993个元素,说明它内部并没有保证线程安全! 当我们在并发情况下使用这些容器时就需要考虑线程安全问题,替换线程安全的容器类(如ConcurrentHashMap, Vector, CopyOnWriteArrayList等)或者使用额外的同步手段如加锁!

    扩展

    在单线程遍历时,如果想删除某个元素,可以使用iterator.remove()

    ArrayList<String> list = new ArrayList<>();
    for (int i = 0; i < 5; i++) {
        list.add("list->" + (i + 1));
    }
    
    Iterator<String> iterator = list.iterator();
    while (iterator.hasNext()) {
        String next = iterator.next();
        if (next.equals("list->3")) {
            iterator.remove();
        }
    
        System.out.println(next);
    }
    System.out.println(list);
    
    ConcurrentModificationException
    对于ArrayList而言,你也可以调用lsitIterator()方法获取内部的ListIterator从而进行添加,插入操作:
    ArrayList<String> list = new ArrayList<>();
            for (int i = 0; i < 5; i++) {
                list.add("list->" + (i + 1));
            }
    
            ListIterator<String> iterator = list.listIterator();
            while (iterator.hasNext()) {
                String next = iterator.next();
                if (next.equals("list->3")) {
                    iterator.remove();
    
                }
    
                System.out.println(next);
                iterator.add("list->7");
            }
            System.out.println(list);
    
    ConcurrentModificationException
    关注我,这里只有干货!

    相关文章

      网友评论

        本文标题:谈一谈ConcurrentModificationExcepti

        本文链接:https://www.haomeiwen.com/subject/pomwiqtx.html