谈一谈ConcurrentModificationException

ConcurrentModificationException

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

前言

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()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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从而进行添加,插入操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
关注我,这里只有干货!

×

谢谢你支持我分享知识

扫码支持
扫码打赏,心意已收

打开微信扫一扫,即可进行扫码打赏哦

文章目录
  1. 1. 前言
  2. 2. 源码解析
  3. 3. 扩展
欢迎扫描左方二维码跟作者交流.