程序员

谈一谈ConcurrentModificationExcepti

2019-04-09  本文已影响0人  jsbintask
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
关注我,这里只有干货!
上一篇下一篇

猜你喜欢

热点阅读