谈谈fail-fast与fail-safe是什么以及工作机制

前面回顾:
HashMap的工作原理

 今天,我们来谈谈fail-fast与fail-safe是什么以及工作机制

fail-fast是什么?

fail-fast的字面意思是“快速失败”。当我们在遍历集合元素的时候,经常会使用迭代器,但在迭代器遍历元素的过程中,如果集合的结构被改变的话,就会抛出异常,防止继续遍历。这就是所谓的快速失败机制。

下面我们来看看官方文档在HashMap这个集合中,它是怎么解释fail-fast的(如下图):


image

意思就是说,当Iterator这个迭代器被创建后,除了迭代器本身的方法(remove)可以改变集合的结构外,其他的因素如若改变了集合的结构,都被抛出ConcurrentModificationException异常。

请在继续看官方的描述:

image

意思就是说:迭代器的快速失败行为是不一定能够得到保证的,一般来说,存在非同步的并发修改时,不可能做出任何坚决的保证的。但是快速失败迭代器会做出最大的努力来抛出ConcurrentModificationException。因此,编写依赖于此异常的程序的做法是不正确的。正确的做法应该是:迭代器的快速失败行为应该仅用于检测程序中的bug.

稍微总结下:fail-fast,即快速失败机制,它是java集合中的一种错误检测机制,当多个线程(当个线程也是可以滴),在结构上对集合进行改变时,就有可能会产生fail-fast机制。

这里,我解释下什么是结构上的改变。
例如集合上的插入和删除就是结构上的改变,但是,如果是对集合中某个元素进行修改的话,并不是结构上的改变哦。

下面,我们来演示下在单线程的环境下,fail-fast抛出异常的实例:

        for(int i = 10; i < 100; i++){
        map.put(i, i);
    }
    List<Integer> list = new ArrayList<>();
    for(int i = 0; i < 20; i++){
        list.add(i);
    }
    Iterator<Integer> it = list.iterator();
    int temp = 0;
    while(it.hasNext()){
        if(temp == 3){
            temp++;
            list.remove(3);
        }else{
            temp++;
            System.out.println(it.next());
        }
    }
}

打印结果:

image

结果分析:因为当temp==3的时候,执行list.remove()方法,集合的结构被改变了,所以再次遍历迭代器的时候,就会抛出异常。


fail-fast的工作原理

我们首先先来看下源码:

image

分析:从源码我们可以发现,迭代器在执行next()等方法的时候,都会调用checkForComodification()这个方法,查看modCount==expectedModCount?如果相等则抛出异常。

expectedModcount:这个值在对象被创建的时候就被赋予了一个固定的值modCount。也就是说这个值是不变的。也就是说,如果在迭代器遍历元素的时候,如果modCount这个值发生了改变,那么再次遍历时就会抛出异常。
什么时候modCount会发生改变呢?

这次就不带大家看源码了。其实当我们对集合的元素的个数做出改变的时候,modCount的值就会被改变,如果删除,插入。但修改则不会。


fail-fast的一些处理方法

如果我们不希望在迭代器遍历的时候因为并发等原因,导致集合的结构被改变,进而可能抛出异常的话,我们可以在涉及到会影响到modCount值改变的地方,加上同步锁(synchronized),或者直接使用
Collections.synchronizedList来解决。


fail-fast就先讲到这里,下面简单讲讲fail-safe与fail-fast的区别

当我们对集合结构上做出改变的时候,fail-fast机制就会抛出异常。但是,对于采用fail-safe机制来说,就不会抛出异常(大家估计看到safe两个字就知道了)。

这是因为,当集合的结构被改变的时候,fail-safe机制会在复制原集合的一份数据出来,然后在复制的那份数据遍历。

因此,虽然fail-safe不会抛出异常,但存在以下缺点:

  1. 复制时需要额外的空间和时间上的开销。

  2. 不能保证遍历的是最新内容。

如果你习惯在微信公众号看技术文章想要获取更多资源的同学欢迎关注我的公众号:苦逼的码农每天向你推送 各种视频资源,电子书、 技术文章以及和面试有关的 算法专题 每日一题

希望看完让你有所收获,便是我最大的回报!

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 快速失效与安全失效,是针对迭代数据结构过程出现的两种说法。 Iterator的安全失败是基于对底层集合做拷贝,因此...
    乐百事52淑熙阅读 6,850评论 0 0
  • 在没有Iterator的情况下我们可以用for循环,那为什么我们要使用Iterator呢? 为什么需要迭代器Ite...
    扈扈哈嘿阅读 8,600评论 2 14
  • 1.概念 fail-fast 机制是java集合(Collection)中的一种错误机制。当多个线程对同一个集合的...
    _fatef阅读 3,486评论 0 0
  • 课后感言: 听完老师的《删除1000好友启示录:割舍越多得到越多,退后原来是向前》这段音频,感觉这确实是需要突破的...
    宋亿青s六中换阅读 2,607评论 0 0
  • 日子也依旧平平淡淡地过着,但好像又有什么不一样了。果然天气变好人的心情也会转变的吗?从前两天妖风肆虐梅雨来袭突然变...
    爱吃坚果的松鼠小姐阅读 3,157评论 0 0