快速失败(fail—fast):

在用迭代器遍历一个集合对象时,如果遍历过程中对集合对象的内容进行了修改(增加、删除、修改),则会抛出Concurrent Modification Exception。

原理:迭代器在遍历时直接访问集合中的内容,并且在遍历过程中使用一个 modCount 变量。集合在被遍历期间如果内容发生变化,就会改变modCount的值。每当迭代器使用hashNext()/next()遍历下一个元素之前,都会检测modCount变量是否为expectedmodCount值,是的话就返回遍历;否则抛出异常,终止遍历。

注意:这里异常的抛出条件是检测到 modCount!=expectedmodCount 这个条件。如果集合发生变化时修改modCount值刚好又设置为了expectedmodCount值,则异常不会抛出。因此,不能依赖于这个异常是否抛出而进行并发操作的编程,这个异常只建议用于检测并发修改的bug。

场景:java.util包下的集合类都是快速失败的,不能在多线程下发生并发修改(迭代过程中被修改)。

安全失败(fail—safe):

采用安全失败机制的集合容器,在遍历时不是直接在集合内容上访问的,而是先复制原有集合内容,在拷贝的集合上进行遍历。

原理:由于迭代时是对原集合的拷贝进行遍历,所以在遍历过程中对原集合所作的修改并不能被迭代器检测到,所以不会触发Concurrent Modification Exception。

缺点:基于拷贝内容的优点是避免了Concurrent Modification Exception,但同样地,迭代器并不能访问到修改后的内容,即:迭代器遍历的是开始遍历那一刻拿到的集合拷贝,在遍历期间原集合发生的修改迭代器是不知道的。

场景:java.util.concurrent包下的容器都是安全失败,可以在多线程下并发使用,并发修改。

那么平常我们如何去规避这种情况呢?

这里有两种解决方案:

方案一:在遍历过程中所有涉及到改变modCount值得地方全部加上synchronized或者直接使用Collections.synchronizedList(不推荐)

方案二:使用CopyOnWriteArrayList来替换ArrayList。

CopyOnWriteArrayList为什么能解决这个问题呢?CopyOnWrite容器即写时复制的容器。通俗的理解是当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。CopyOnWriteArrayList中add/remove等写方法是需要加锁的,目的是为了避免Copy出N个副本出来,导致并发写。但是。CopyOnWriteArrayList中的读方法是没有加锁的。

我们只需要记住一句话,那就是CopyOnWriteArrayList是线程安全的,所以我们在多线程的环境下面需要去使用这个就可以了。关于CopyOnWriteArrayList更加深入的用法,会在以后的章节中去解释说明。

fail-fast快速失败案例:

1 public classFailFastDemo {2 private static List list = new ArrayList();3

4 public static voidmain(String[] args) {5 //两个线程对同一个ArrayList进行操作

6 newThreadOne().start();7 newThreadTwo().start();8 }9 //输出list中的值

10 private static voidprintAll(){11 try{12 String value = null;13 Iterator iterator =list.iterator();14 while(iterator.hasNext()){15 value =(String) iterator.next();16 System.out.println("list 中的值:"+value);17 Thread.sleep(1000);18 }19 } catch(InterruptedException e) {20 e.printStackTrace();21 }22 }23 //线程一:向list中依次添加数据,然后printAll整个list

24 private static class ThreadOne extendsThread{25 public voidrun() {26 for (int i = 0; i < 6; i++) {27 list.add(String.valueOf("线程一:Java的架构师技术栈"+i));28 printAll();29 }30 }31 }32 //线程二:对ArrayList进行同样的操作

33 private static class ThreadTwo extendsThread{34 public voidrun() {35 for (int i = 0; i < 6; i++) {36 list.add(String.valueOf("线程二:Java的架构师技术栈"+i));37 printAll();38 }39 }40 }41 }

更改后:使用CopyOnWriteArrayList替代ArrayList来避免异常发生

1 public classFailFastDemo {2 //private static List list = new ArrayList();3 //使用CopyOnWriteArrayList替代ArrayList

4 private static List list = new CopyOnWriteArrayList();5 public static voidmain(String[] args) {6 //两个线程对同一个ArrayList进行操作

7 newThreadOne().start();8 newThreadTwo().start();9 }10 //输出list中的值

11 private static voidprintAll(){12 try{13 String value = null;14 Iterator iterator =list.iterator();15 while(iterator.hasNext()){16 value =(String) iterator.next();17 System.out.println("list 中的值:"+value);18 Thread.sleep(1000);19 }20 } catch(InterruptedException e) {21 e.printStackTrace();22 }23 }24 //线程一:向list中依次添加数据,然后printAll整个list

25 private static class ThreadOne extendsThread{26 public voidrun() {27 for (int i = 0; i < 6; i++) {28 list.add(String.valueOf("线程一:Java的架构师技术栈"+i));29 printAll();30 }31 }32 }33 //线程二:对ArrayList进行同样的操作

34 private static class ThreadTwo extendsThread{35 public voidrun() {36 for (int i = 0; i < 6; i++) {37 list.add(String.valueOf("线程二:Java的架构师技术栈"+i));38 printAll();39 }40 }41 }42 }

运行结果无异常:

fail safe java_Java中快速失败(fail-fast)和安全失败(fail-safe)的区别?相关推荐

  1. overloaded java_java中重写(Override)和重载(overloaded)的区别

    JAVA中重载方法和重写方法的区别经常在初级程序员面试中被提及,它们的区别在于重写发生在子父类中,而重载发生在一个类中. 重写是子类的方法名和父类相同(传入参数的类型.数量.顺序也要相同),如下: c ...

  2. 如何在Go中编写防弹代码:不会失败的服务器工作流程

    by Tal Kol 通过塔尔科尔 如何在Go中编写防弹代码:不会失败的服务器工作流程 (How to write bulletproof code in Go: a workflow for ser ...

  3. [单片机][at32][填坑日记] [USB卡包] usb上电过程中快速发包导致卡包(终章)

    文章目录 一.原因造成如下: 1. 串口外设优先级大于USB中断(USBOTG_IRQn),导致串口数据打断USB,致使PC或MCU丢包. 2. 当PC请求usb设备描述符字符串时,USB的其他通道不 ...

  4. Istio-0.8.0在Minikube环境中快速启动Bookinfo示例

    Istio-0.8.0在Minikube环境中快速启动Bookinfo示例 之前发表了从零开始应用Istio--入门示例,使用的istio版本比较低,在0.8.0版本下发现很多命令不一样了,所以总结一 ...

  5. cassandra本地连接失败_本地网络发现失败的解决方法连接到OS X中的服务器的问题 | MOS86...

    本地联网通常在Mac上完美无缺,这就是为什么某些用户可能会遇到OS X优胜美地的一些最恶化的问题与网络连接有关.其中一些可能涉及更广泛的连接和Wi-Fi功能问题,以及其他可能影响一般LAN网络功能的能 ...

  6. 如何在工作中快速成长?致工程师的10个简单技巧

    如何在工作中快速成长?致工程师的10个简单技巧 阿里妹导读:阿里有句非常经典的土话,"今天的最好表现,是明天的最低要求."如何挖掘潜能.发现更好的自己?今天,阿里巴巴高级无线开发专 ...

  7. 跨进程实现在Tree中快速定位节点

    跨进程实现在Tree中快速定位节点 --------------------------------------------------------------------------------   ...

  8. 泰勒级数 快速傅里叶变换(Fast Fourier Transfor FFT)

    泰勒公式(泰勒展开式)通俗+本质详解 泰勒公式(泰勒展开式)通俗+本质详解_吴明磊的博客-CSDN博客_泰勒公式 泰勒(Taylor)展开式(泰勒级数) 泰勒(Taylor)展开式(泰勒级数)_mji ...

  9. Laragon 在Windows中快速搭建Laravel本地开发环境

    1.应用场景 主要用于快速搭建开发环境,帮助快速开发或者验证一些代码执行等. 优点: 功能更加强大, 更加简便好用 2.学习/操作 简介 对于那些使用 Windows 操作系统的同学来说,Homest ...

最新文章

  1. 通过创建 HttpCookie 对象的实例编写 Cookie
  2. 2020版北大核心期刊目录_榜单|2020武大版核心期刊RCCSE高职高专成高院校学报类自然科学综合、社会科学综合学科权威、核心及准核心期刊目录...
  3. 了解DELL的raid卡电池相关信息
  4. 前端的百度地图的api的使用
  5. angular2、ng2 http get post 传参
  6. RocketMQ各角色介绍
  7. mysql delete 表关联删除数据_mysql delete 多表连接删除功能
  8. Java代码内容概述
  9. 卷积神经网络_mnist
  10. Java微信小程序发送服务通知
  11. IDEA生成SerialVersionUID
  12. php投影,投影效果怎么做?PS制作逼真的投影效果
  13. LLC谐振电路(一) 整流电路总结
  14. CSS盒模型之内边距、边框、外边距 十九问(持续更新)
  15. 云流化像素流技术解决方案之虚拟仿真系统
  16. Windows安装TortoiseSVN
  17. 多传感器融合的四种经典结构
  18. 我的Blog——python封装为exe的注意事项(封装exe看这一篇基本就够了)
  19. 如何压缩jpg图片大小
  20. 2022还不知道登陆邮箱账号怎么填写?个人邮箱登录注册流程看详解

热门文章

  1. MySQL下载与MySQL安装图解(MySQL5.7与MySQL8.0)
  2. gbdt xgboost 贼难理解!
  3. Unity 类似FingerGestures 的相机跟随功能
  4. Spring 4 官方文档学习(十一)Web MVC 框架之异常处理
  5. springMVC,mybatis配置事务
  6. bootstrap-fileupload-上传文件控件
  7. asp.net 程序,当发生找不到文件的错误时,如何正确定位是哪个文件?
  8. const成员或者引用成员必须使用构造函数初始化列表的方式
  9. 结对子作业 四则运算 V2.0
  10. JavaScript编程:文档对象模型DOM