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 ...
随机推荐
- ### Error querying database. Cause: java.lang.IllegalArgumentException: invalid comparison: cn.xiaojian.blog.po.BlogType and java.lang.String ### Cause: java.lang.IllegalArgumentException: ...
### Error querying database. Cause: java.lang.IllegalArgumentException: invalid comparison: cn.xiaoj ...
- Notepad++中安装json格式化插件
在线工具固然好,一旦没网就凉凉 Notepad++编辑器中提供了 json 数据格式化显示的插件 安装插件过程如下: 注意: 安装过程需要联网状态 插件安装过程会自动退出程序,等待几秒钟后插件安装完成 ...
- 【转】15个超炫的HTML5效果
英文原文:http://www.hongkiat.com/blog/15-html5-experiments/ 翻译:iteye 乔布斯没有给Flash任何机会,微软新推出的Windows 8 ...
- 【转】基于ArcGIS for javascript api 轨迹回放
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/stri ...
- 悄摸直播(二)—— 播流器实现(拉取rtmp服务器中的数据流,播放直播画面)
悄摸直播 -- JavaCV实现本机摄像头画面远程直播 播流器 一.功能说明 从rtmp服务器中获取视频流数据 + 展示直播画面 二.代码实现 /** * 播流器 * @param inputPath ...
- C#.Net ComboBox控件设置DropDownList之后背景颜色问题,以及发现的微软的一个BUG
先说背景颜色问题怎么处理. C#.Net WinForm中如果设置ComboBox的DropDownStyle为DropDownList,控件背景色会变成灰色,并且这个时候ComboBox控件的Bac ...
- Scala实践7
一.类 1.1简单类和无参方法 类的定义通过class关键字实现 scala> class Dog { | private var leg = 4 | def shout(content: St ...
- JS的var和let的区别(详细讲解)
let是ES6新增的,它主要是弥补var的缺陷,你也可以把let看做var的升级版.下面我就来详细讲讲var和let的区别 相同点: var和let都有函数级作用域 不同点: (1)var是全局作用域 ...
- Spring Boot2 系列教程 (六) | 使用 JdbcTemplates 访问 Mysql
前言 如题,今天介绍 springboot 通过jdbc访问关系型mysql,通过 spring 的 JdbcTemplate 去访问. 准备工作 SpringBoot 2.x jdk 1.8 mav ...
- KMO检验和Bartlett球形检验
KMO检验和Bartlett球形检验因子分析前,首先进行KMO检验和巴特利球体检验,KMO检验系数>0.5,(巴特利特球体检验的x2统计值的显著性概率)P值<0.05时,问卷才有结构效度, ...