ArrayList 并发操作 ConcurrentModificationException 异常
1、故障现象
ArrayList在迭代的时候如果同时对其进行修改就会抛出java.util.ConcurrentModificationException异常
2、故障代码
public class ArrayListTest {
public static void main(String[] args) {
List<String> lists = new ArrayList<>();
lists.add("a");
lists.add("b");
Iterator<String> iterator = lists.iterator();
while (iterator.hasNext()) {
String next = iterator.next();
if (next == "b") {
lists.remove(next);
}
}
}
}
异常截图

3、导致原因
通过查看异常,发现异常出现的位置在 java.util.ArrayList类的内部类Itr中的checkForComodification方法中
/**
* An optimized version of AbstractList.Itr
*/
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
Itr() {}
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
@Override
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {
Objects.requireNonNull(consumer);
final int size = ArrayList.this.size;
int i = cursor;
if (i >= size) {
return;
}
final Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length) {
throw new ConcurrentModificationException();
}
while (i != size && modCount == expectedModCount) {
consumer.accept((E) elementData[i++]);
}
// update once at end of iteration to reduce heap write traffic
cursor = i;
lastRet = i - 1;
checkForComodification();
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
通过查看代码发现如果 modCount和expectedModCount不相等就会导致抛出异常。
modCount是修改记录数,expectedModCount是期望修改记录数,初始化时expectedModCount=modCount。
ArrayList集合的add和remove操作都有对modCount++操作,就会导致expectedModCount和modCount值不相等从而产生ConcurrentModificationException异常
4、解决方案
解决方案1:使用iterator的remove操作替代ArrayList集合自己的remove操作
public class ArrayListTest {
public static void main(String[] args) {
List<String> lists = new ArrayList<>();
lists.add("a");
lists.add("b");
Iterator<String> iterator = lists.iterator();
while (iterator.hasNext()) {
String next = iterator.next();
if (next == "b") {
iterator.remove();
}
}
}
}
分析:通过查看iterator的remove方法发现,其实还是调用了ArrayList集合的remove方法移除元素,但是会使
expectedModCount=modeCount所以不会抛出ConcurrentModificationException异常
解决方案2:使用JUC concurrent包中CopyOnWriteArrayList并发集合类
public class ArrayListTest {
public static void main(String[] args) {
List<String> lists = new CopyOnWriteArrayList<>();
lists.add("a");
lists.add("b");
Iterator<String> iterator = lists.iterator();
while (iterator.hasNext()) {
String next = iterator.next();
if (next == "b") {
lists.remove(next);
System.out.println(lists);
}
}
}
}
因为迭代器中没有checkForComodification操作,并且集合的add和remove方法中都通过ReentrantLock加锁保证并发操作下的安全性。
5、优化建议
在对ArrayList集合进行并发操作时尽量使用CopyOnWriteArrayList集合类代替
ArrayList 并发操作 ConcurrentModificationException 异常的更多相关文章
- 深入浅出 Java Concurrency (36): 线程池 part 9 并发操作异常体系[转]
并发包引入的工具类很多方法都会抛出一定的异常,这些异常描述了任务在线程池中执行时发生的例外情况,而通常这些例外需要应用程序进行捕捉和处理. 例如在Future接口中有如下一个API: java.uti ...
- Java并发编程:Java ConcurrentModificationException异常原因和解决方法
Java ConcurrentModificationException异常原因和解决方法 在前面一篇文章中提到,对Vector.ArrayList在迭代的时候如果同时对其进行修改就会抛出java.u ...
- Java ConcurrentModificationException异常原因和解决方法
Java ConcurrentModificationException异常原因和解决方法 在前面一篇文章中提到,对Vector.ArrayList在迭代的时候如果同时对其进行修改就会抛出java.u ...
- java集合--java.util.ConcurrentModificationException异常
ConcurrentModificationException 异常:并发修改异常,当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常.一个线程对collection集合迭代,另一个线程对Co ...
- 【转】Java ConcurrentModificationException 异常分析与解决方案--还不错
原文网址:http://www.2cto.com/kf/201403/286536.html 一.单线程 1. 异常情况举例 只要抛出出现异常,可以肯定的是代码一定有错误的地方.先来看看都有哪些情况会 ...
- 【转】Java ConcurrentModificationException异常原因和解决方法
原文网址:http://www.cnblogs.com/dolphin0520/p/3933551.html Java ConcurrentModificationException异常原因和解决方法 ...
- 修改List报ConcurrentModificationException异常原因分析
使用迭代器遍历List的时候修改List报ConcurrentModificationException异常原因分析 在使用Iterator来迭代遍历List的时候如果修改该List对象,则会报jav ...
- (转)Java ConcurrentModificationException异常原因和解决方法
转载自:http://www.cnblogs.com/dolphin0520/p/3933551.html 在前面一篇文章中提到,对Vector.ArrayList在迭代的时候如果同时对其进行修改就会 ...
- 在ConcurrentModificationException异常上的联想
1.什么是ConcurrentModificationException? 大家都听说过快速报错fast-fail吧,fast-fail的发生就是说明发生了ConcurrentModification ...
随机推荐
- Django之models高级进阶技术详解
目录 一.常用字段 1.AutoField 2.IntegerField 3.CharField 4.自定义及使用char 5.DateField 6.DateTimeField 二.字段合集 三.字 ...
- Jquery图片上传功能整理
最近在做一个图片上传到服务器的功能,之前基本没有什么JS的经验,用的也是网上的插件.做了一个星期才把他弄好,现在做一下总结,方便以后查看. 用的插件是WebUploader,上面有很多例子,我找的例子 ...
- UGUI源码之EventSystem
今天研究下UGUI的源码,先从EventSystem入手.EventSystem是用来处理点击.键盘输入以及触摸等事件的. 1.BaseInputModule EventSystem开头声明了两个变量 ...
- pqsql 防注入
在数据库查询时经常会遇到根据传入的参数查询内容的情况,传入的参数有可能会带有恶意代码,比如or 1=1,这样where判断为true,就会返还所有的记录.为了解决这个问题,可以在参数外面包一层单引号, ...
- Mysql中使用mysqldump进行导入导出sql文件
纪念工作中的第一次删库跑路的经历 今天接到一个任务,是将一个测试库数据导到另一个测试库,然而我们公司的数据库是不让直连的,所以只能通过远程连接进行导库操作. 老大布置任务的时候让用dump命令进行操作 ...
- jS Ajax 上传文件报错"Uncaught TypeError: Illegal invocation"
使用jquery ajax异步提交文件的时候报Uncaught TypeError :Illegal invocation错误,报错信息如图: 错误原因: jQuery Ajax 上传文件处理方式,使 ...
- 【PCIE-3】---PCIE设备的枚举扫描(经典好文)
前面两个小节大致总结了下PCIE的基本知识,算是扫盲篇吧.本文主要总结PCIE设备的枚举扫描过程,此部分才是PCIE模块的重点,无论是在BIOS下还是系统驱动下都会用到. 按照国际惯例,先列问题: 1 ...
- 沈阳网络赛 F - 上下界网络流
"Oh, There is a bipartite graph.""Make it Fantastic." X wants to check whether a ...
- 每天玩转3分钟 MyBatis-Plus - 2. 普通查询
每天玩转3分钟 MyBatis-Plus - 1. 配置环境 每天玩转3分钟 MyBatis-Plus - 2. 普通查询 mybatis-plus的查询功能非常强大, 这一篇,我们来看下mybati ...
- Java故障定位方法总结
多线程并发,程序执行速度较快,使用简单断点不能够定位到出错的线程: 通过打印日志,不断精确定位故障的位置和导致故障的原因. 在断点处设置condition为Thread.currentThread() ...