平常在使用集合的时候肯定会遇到过遍历删除集合中的某些元素,哪么在进行操作的时候大家有 没有遇到过什么问题呢?最近在使用集合进行遍历删除元素的时候,我就碰到了这个异常:java.util.ConcurrentModificationException。该异常是一个并发修改异常,于是引起我了的思考。

平常会使用遍历删除的几种方式:

  1. 通过增强for删除符合要求的元素(一个或者多个)
  • 会出现异常java.util.ConcurrentModificationException
  • 但假如加上break的话异常就不会出现,因为不会影响到后续的元素。
  public void listRemove(){List<Integer> list = new ArrayList<>();for (Integer i:list){list.remove();}}
************************************************  public void listRemove(){List<Integer> list = new ArrayList<>();for (Integer i:list){list.remove();break;}}
复制代码
  1. 通过普通for删除符合要求元素
  • 这里虽然不会出现异常,但是你会发现会有些元素没有被删除掉的。原因是:比如我添加10个元素,然后把第三个删除掉了。那么原本下标为4的元素就会变成下标为3的元素了。如此类推就会出现数据不正确的情况。
  public void listRemove(){List<Student> students = new ArrayList<>();student.add........ // 添加元素就略了for (int i = 0; i<list.size();i++){Student s  = list.get(0);list.remove(s);}}
复制代码
  1. 通过Iteator删除符合要求的元素
  • 假如这里删除用的是List的remove方法还是会照样抛出java.util.ConcurrentModificationException
  • 如果不想抛出异常又能正确删除的话,建议使用Itreator的remove方法。
   public void listRemove(){List<Student> students = new ArrayList<>();student.add........ // 添加元素就略了Itreator<Student> it = students.Itreator();while(it.hasNext()){Student student = it.next();if (student.getAge() == 10){it.remove();}}}
复制代码

那么什么会出现以上的情况呢?这就跟Fail-Fast机制有关了。

Fail-Fast机制是Java集合中的一种错误机制。当多个线程对同一个集合的内容进行操作时,就会发生Fail-Fast事件。

例如:当某一个线程A通过iterator去遍历某集合的过程中,若该集合的内容被其他线程所改变了;那么线程A访问集合时,就会抛出ConcurrentModificationException异常,产生fail-fast事件。

ConcurrentModificationException异常:当方法检测到对象的并发修改,但不允许这种修改时就会抛出这个异常。需要注意的是:如果单线程违反了规则,同样也会抛出这个异常

迭代器的快速失败行为无法得到保证,它不能保证一定会出现该错误,但是快速失败操作会尽最大努力抛出ConcurrentModificationException异常,所以因此,为提高此类操作的正确性而编写一个依赖于此异常的程序是错误的做法

结论:ConcurrentModificationException异常应该仅用于检测BUG。

那么为什么Itreator修改就不会抛出ConcurrentModificationException异常呢?

Itreator是工作在一个独立的线程中,并有一个mutex锁(互斥锁)。

  • synchronized修饰的同步代码块就是一个互斥锁。

线程在进入同步代码块之前会自动获取锁,并且在退出同步代码块时会自动释放锁,当某个线程请求一个由其他线程持有的锁时,发出请求的线程就会阻塞。互斥锁其实提供了一种原子操作,让所有线程以串行的方式执行同步代码块。

  • Iterator被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,

  • 所以当索引指针往后移动的时候就找不到要迭代的对象,所以按照 fail-fast 原则 Iterator会马上抛出java.util.ConcurrentModificationException 异常。

  • 所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。但你可以使用 Iterator 本身的方法 remove() 来删除对象,Iterator.remove()方法会在删除当前迭代对象的同时维护索引的一致性。

但如果你的Collection/Map对象实际只有一个或两个元素的时候,ConcurrentModificationException异常并不会抛出。


本文内容参考自:www.hollischuang.com/archives/33

转载于:https://juejin.im/post/5b7cc7ce51882542b45dd220

Fail - Fast机制相关推荐

  1. Java - Java集合中的快速失败Fail Fast 机制

    文章目录 什么是 fail-fast 源码解读 Itr 为什么对集合的结构进行修改会发生并发修改异常-源码分析 修改方法之 remove 修改方法之 add 案例分享 [案例一] [案例二] [案例三 ...

  2. Java - Java集合中的安全失败Fail Safe机制 (CopyOnWriteArrayList)

    文章目录 Pre 概述 fail-safe的容器-CopyOnWriteArrayList add remove函数 例子 缺陷 使用场景 Pre Java - Java集合中的快速失败Fail Fa ...

  3. 【转载】ArrayList 中数据删除 fail fast

    2019独角兽企业重金招聘Python工程师标准>>> 本文转载自http://shift-alt-ctrl.iteye.com/blog/1839147 在循环arrayLlist ...

  4. 聊聊hikari与tomcat jdbc pool的fail fast

    序 本文主要研究在中途数据库挂的情况下,hikari与tomcat jdbc pool的fail fast情况. 实验代码 @Testpublic void testDatabaseDownAndUp ...

  5. 【springcloud问题】Could not locate PropertySource and the fail fast property is set, failing

    问题描述:使用springcloud的本地配置中心时出现:Could not locate PropertySource and the fail fast property is set, fail ...

  6. Fail Fast与Fail Safe的区别

    Fail Fast Fail Fast Iterator在遍历集合时,若该集合发生了结构性的改变,则将抛出 ConcurrentModification 异常.例如: Map<String, S ...

  7. 什么是Fail Fast和Fail Safe?

    这里是目录标题 1. Fail Fast a. 概念 b. 原理 c. 关注点 d. 注意 2. Fail Safe a. 概念 b. 原理 3. Fail Fast 和 Fail Safe的区别 1 ...

  8. Java Review - ArrayList 源码解读

    文章目录 概述 方法的执行效率 源码剖析 底层数据结构 -数组 构造函数 自动扩容机制 set() get add()/addAll() remove() trimToSize() indexOf() ...

  9. java arraylist 源代码_Java中ArrayList源码浅析

    ArrayList基本使用 public class ArrayListTest { public static void main(String[] args) { List list = new ...

最新文章

  1. 迈出编程第一步!必知必会的10个编程技巧及查错方法
  2. (转)OpenCV版本的摄像机标定
  3. python 装饰器 生成器 迭代器和闭包
  4. 拍不完的脑袋:推荐系统打压保送重排策略
  5. 2G3G要退网了,但没必要着急换5G手机
  6. af_netlink_Linux Netlink通信机制详解(上)
  7. 游戏社交不足怎么办? 游戏发行中的社交化运营经验分享
  8. Linux下的uniq,head,tail,cut,paste
  9. 编写一个基于控制台的聊天室程序
  10. Linux上PyCharm报错及解决:ImportError: No module named 'sklearn'
  11. linux之文本编辑器
  12. mysql有rollup函数,Mysql,Oracle使用rollup函数完成行列统计
  13. 台式机标准计算机配置清单,台式机组装,教您组装电脑高配置清单
  14. 【Python语音分析】从绘制好看的波形图和语谱图开始
  15. 手把手教会你视频转文字怎么操作,快来get
  16. 人生各个年龄段的称谓
  17. python基于PHP+MySQL的学生社团管理系统
  18. 【日志分析】Linux日志分析
  19. python days03
  20. 自定义Toast、程序退出时Toast也退出、Toast的用法

热门文章

  1. python实现括号分组
  2. Spring结合Quartz实现多任务定时调用(转载)
  3. 导购效果跟踪: SPM
  4. [BAT]TASKKILL 杀进程
  5. 外贸网站建设(转自xmfish)
  6. 【hive】Hive的安装过程与配置的详解
  7. JAVA继承重写的规则
  8. python调用usb摄像头黑屏_ORB-SLAM2编译安装和USB摄像头例程运行
  9. 跳转后退_羽毛球后退步法常见问题及解决方法
  10. 大数据自学好还是培训好?