java.util.ConcurrentModificationException详解
一、异常产生
当我们迭代一个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详解相关推荐
- java多线程学习-java.util.concurrent详解
http://janeky.iteye.com/category/124727 java多线程学习-java.util.concurrent详解(一) Latch/Barrier 博客分类: java ...
- java.util包详解
介绍Java的实用工具类库java.util包.在这个包中,Java提供了一些实用的方法和数据结构.本章介绍Java的实用工具类库java.util包.在这个包中,Java提供了一些实用的方法和数据结 ...
- java多线程学习-java.util.concurrent详解(一) Latch/Barrier
2019独角兽企业重金招聘Python工程师标准>>> Java1.5提供了一个非常高效实用的多线程包:java.util.concurrent, 提供了大量高级工具,可以帮助开发者 ...
- java多线程详解 六_java多线程学习-java.util.concurrent详解(六) Exchanger
转载于:http://janeky.iteye.com/blog/769965 我们先来学习一下JDK1.5 API中关于这个类的详细介绍: "可以在pair中对元素进行配对和交换的线程的同 ...
- java多线程学习-java.util.concurrent详解(五) ScheduledThreadPoolExecutor
转载于:http://janeky.iteye.com/blog/769965 我们先来学习一下JDK1.5 API中关于这个类的详细介绍: "可另行安排在给定的延迟后运行命令,或者定期执行 ...
- JAVA.UTIL.ARRAYLIST 详解
[size=medium][color=red][b]java.util.ArrayList[/b][/color][/size] [size=medium] 数组和数组列表之间有着重大的区别.数组是 ...
- Java并发包-java.util.concurrent详解
转载自https://blog.csdn.net/axi295309066/article/details/65665090 一.阻塞队列BlockingQueue BlockingQueue通常用于 ...
- java.util.ConcurrentModificationException 异常问题详解
java.util.ConcurrentModificationException 异常问题详解 参考文章: (1)java.util.ConcurrentModificationException ...
- 【集合类】 1 java.util.ConcurrentModificationException异常详解ArrayListCopyOnWriteArrayList原理探究
环境:JDK 1.8.0_111 文章目录 概述 一.单线程情况下问题分析及解决方案 1.1 问题复现 1.2 问题原因分析 1.3 问题解决方案 二. 多线程情况下的问题分析及解决方案 2.1 问题 ...
最新文章
- python进程间通信 listener_python进程间通信之Queue
- 报名 | 第三期医工结合系列研讨会:科研领域的知识产权保护
- python中怎么打开文件_python如何打开文件
- python中lines是什么类型_Python中splitlines()方法的使用简介
- 【华为云技术分享】玩转小熊派BearPi(一)使用STM32CubeMX + HAL点亮一个LED
- 继承的原理java_Java继承和多态的原理
- 硬盘、服务器、RAID磁盘阵列
- 养老金中除以139是什么意思?
- IDEA的Database表的基本操作
- 跟着【莫烦python】学习神经网络框架TensorFlow和Pytorch学习笔记
- Docker安装Tomcat,安装elasticsearch+kibana
- IP地址到底是什么?
- 去除win10桌面图标快捷方式小箭头
- 对Linux内核tty设备的一点理解(转)
- HARK学习(七)--ConstantLocalization
- 红尘阡陌,那抹温暖的烟火
- 深入探索Android内存优化(炼狱级别)
- 彻底搞懂基于Open3D的点云处理教程!
- 张益唐111页零点猜想论文出炉!自称比孪生素数猜想意义更大,每天思考12小时被太太骂...
- 串口调试助手之间通信和接受、发送数据