一、异常产生

当我们迭代一个ArrayList或者HashMap时,如果尝试对集合做一些修改操作(例如删除元素),可能会抛出java.util.ConcurrentModificationException的异常。

import java.util.Iterator;
import java.util.List;public class AddRemoveListElement {public static void main(String args[]) {List<String> list = new ArrayList<String>();list.add("A");list.add("B");for (String s : list) {if (s.equals("B")) {list.remove(s);}}//foreach循环等效于迭代器/*Iterator<String> iterator=list.iterator();while(iterator.hasNext()){String s=iterator.next();if (s.equals("B")) {list.remove(s);}}*/    }
}

二、异常原因

ArrayList的父类AbstarctList中有一个域modCount,每次对集合进行修改(增添元素,删除元素……)时都会modCount++

而foreach的背后实现原理其实就是Iterator(关于Iterator可以看Java Design Pattern: Iterator),等同于注释部分代码。在这里,迭代ArrayList的Iterator中有一个变量expectedModCount,该变量会初始化和modCount相等,但如果接下来如果集合进行修改modCount改变,就会造成expectedModCount!=modCount,此时就会抛出java.util.ConcurrentModificationException异常

过程如下图:

三、异常的解决

1、单线程环境

好,现在我们已经基本了解了异常的发送原因了。接下来我们来解决它。
我很任性,我就是想在迭代集合时删除集合的元素,怎么办?

Iterator<String> iter = list.iterator();
while(iter.hasNext()){String str = iter.next();if( str.equals("B") ){iter.remove();}
}

细心的朋友会发现Itr中的也有一个remove方法,实质也是调用了ArrayList中的remove,但增加了expectedModCount = modCount;保证了不会抛出java.util.ConcurrentModificationException异常。

但是,这个办法的有两个弊端
1.只能进行remove操作,add、clear等Itr中没有。
2.而且只适用单线程环境。

2、多线程环境

方法一:迭代前加锁,解决了多线程问题,但还是不能进行迭代add、clear等操作

public class Test2 {static List<String> list = new ArrayList<String>();public static void main(String[] args) {list.add("a");list.add("b");list.add("c");list.add("d");new Thread() {public void run() {Iterator<String> iterator = list.iterator();synchronized (list) {while (iterator.hasNext()) {System.out.println(Thread.currentThread().getName()+ ":" + iterator.next());try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}};}.start();new Thread() {public synchronized void run() {Iterator<String> iterator = list.iterator();synchronized (list) {while (iterator.hasNext()) {String element = iterator.next();System.out.println(Thread.currentThread().getName()+ ":" + element);if (element.equals("c")) {iterator.remove();}}}};}.start();}
}

方法二:采用CopyOnWriteArrayList,解决了多线程问题,同时可以add、clear等操作

public class Test2 {static List<String> list = new CopyOnWriteArrayList<String>();public static void main(String[] args) {list.add("a");list.add("b");list.add("c");list.add("d");new Thread() {public void run() {Iterator<String> iterator = list.iterator();while (iterator.hasNext()) {System.out.println(Thread.currentThread().getName()+ ":" + iterator.next());try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}};}.start();new Thread() {public synchronized void run() {Iterator<String> iterator = list.iterator();while (iterator.hasNext()) {String element = iterator.next();System.out.println(Thread.currentThread().getName()+ ":" + element);if (element.equals("c")) {list.remove(element);}}};}.start();}
}

CopyOnWriteArrayList也是一个线程安全的ArrayList,其实现原理在于,每次add,remove等所有的操作都是重新创建一个新的数组,再把引用指向新的数组。

java.util.ConcurrentModificationException详解相关推荐

  1. java多线程学习-java.util.concurrent详解

    http://janeky.iteye.com/category/124727 java多线程学习-java.util.concurrent详解(一) Latch/Barrier 博客分类: java ...

  2. java.util包详解

    介绍Java的实用工具类库java.util包.在这个包中,Java提供了一些实用的方法和数据结构.本章介绍Java的实用工具类库java.util包.在这个包中,Java提供了一些实用的方法和数据结 ...

  3. java多线程学习-java.util.concurrent详解(一) Latch/Barrier

    2019独角兽企业重金招聘Python工程师标准>>> Java1.5提供了一个非常高效实用的多线程包:java.util.concurrent, 提供了大量高级工具,可以帮助开发者 ...

  4. java多线程详解 六_java多线程学习-java.util.concurrent详解(六) Exchanger

    转载于:http://janeky.iteye.com/blog/769965 我们先来学习一下JDK1.5 API中关于这个类的详细介绍: "可以在pair中对元素进行配对和交换的线程的同 ...

  5. java多线程学习-java.util.concurrent详解(五) ScheduledThreadPoolExecutor

    转载于:http://janeky.iteye.com/blog/769965 我们先来学习一下JDK1.5 API中关于这个类的详细介绍: "可另行安排在给定的延迟后运行命令,或者定期执行 ...

  6. JAVA.UTIL.ARRAYLIST 详解

    [size=medium][color=red][b]java.util.ArrayList[/b][/color][/size] [size=medium] 数组和数组列表之间有着重大的区别.数组是 ...

  7. Java并发包-java.util.concurrent详解

    转载自https://blog.csdn.net/axi295309066/article/details/65665090 一.阻塞队列BlockingQueue BlockingQueue通常用于 ...

  8. java.util.ConcurrentModificationException 异常问题详解

    java.util.ConcurrentModificationException 异常问题详解 参考文章: (1)java.util.ConcurrentModificationException ...

  9. 【集合类】 1 java.util.ConcurrentModificationException异常详解ArrayListCopyOnWriteArrayList原理探究

    环境:JDK 1.8.0_111 文章目录 概述 一.单线程情况下问题分析及解决方案 1.1 问题复现 1.2 问题原因分析 1.3 问题解决方案 二. 多线程情况下的问题分析及解决方案 2.1 问题 ...

最新文章

  1. python进程间通信 listener_python进程间通信之Queue
  2. 报名 | 第三期医工结合系列研讨会:科研领域的知识产权保护
  3. python中怎么打开文件_python如何打开文件
  4. python中lines是什么类型_Python中splitlines()方法的使用简介
  5. 【华为云技术分享】玩转小熊派BearPi(一)使用STM32CubeMX + HAL点亮一个LED
  6. 继承的原理java_Java继承和多态的原理
  7. 硬盘、服务器、RAID磁盘阵列
  8. 养老金中除以139是什么意思?
  9. IDEA的Database表的基本操作
  10. 跟着【莫烦python】学习神经网络框架TensorFlow和Pytorch学习笔记
  11. Docker安装Tomcat,安装elasticsearch+kibana
  12. IP地址到底是什么?
  13. 去除win10桌面图标快捷方式小箭头
  14. 对Linux内核tty设备的一点理解(转)
  15. HARK学习(七)--ConstantLocalization
  16. 红尘阡陌,那抹温暖的烟火
  17. 深入探索Android内存优化(炼狱级别)
  18. 彻底搞懂基于Open3D的点云处理教程!
  19. 张益唐111页零点猜想论文出炉!自称比孪生素数猜想意义更大,每天思考12小时被太太骂...
  20. 串口调试助手之间通信和接受、发送数据

热门文章

  1. PYTHONPATH
  2. HDU1175 连连看
  3. 智产易:商标被驳回,是重新申请比较好,还是驳回复审好?
  4. oracle 常用的 hints
  5. 深度学习中的几个错误率和准确率
  6. JAVA 在线中文API地址
  7. Kubernetes如何使用ReplicationController、Replica Set、Deployment管理Pod
  8. 关键错误,开始菜单和cortana无法工作,注销重新登录我们会修复此问题?
  9. windows 10 关键错误,“开始”菜单无法使用,Cortana无法使用 无法工作的两种解决方法,实测可行
  10. 魔兽初级上手指南快捷键