fail-fast和fail-safe

fail-fast

首先啥是fail-fast?下面引用别人的解释:

在系统设计中,快速失效系统一种可以立即报告任何可能表明故障的情况的系统。快速失效系统通常设计用于停止正常操作,而不是试图继续可能存在缺陷的过程。这种设计通常会在操作中的多个点检查系统的状态,因此可以及早检测到任何故障。快速失败模块的职责是检测错误,然后让系统的下一个最高级别处理错误。

他的意思就是写程序***先考虑异常情况***,如果遇到就直接抛出处理。

public int divide(int divisor,int dividend){
    if(dividend == 0){
        throw new RuntimeException("dividend can't be null");
    }
    return divisor/dividend;
}

例如上面的方法,对除数进行检测如果是0则直接抛出异常,并标明异常原因。这样做的好处就是可以预先识别出一些错误情况,一方面可以避免执行复杂的其他代码,另外一方面,这种异常情况被识别之后也可以针对性的做一些单独处理。

集合中的fail-fast

我们通常说的Java中的fail-fast机制,默认指的是Java集合的一种错误检测机制。当多个线程对部分集合进行结构上的改变的操作时,有可能会产生fail-fast机制,这个时候就会抛出ConcurrentModificationException。下面来看看例子:

        List<Integer> list = new ArrayList<Integer>(){{
           for (int i=1;i<=10;i++){
                add(i);
           }
        }};
        for (Integer integer:list){
            if (integer==5){
                list.remove(integer);
            }
        }

上面使用foreach来遍历list并删除元素值为5的元素,执行结果:

Exception in thread "main" java.util.ConcurrentModificationException
	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
	at java.util.ArrayList$Itr.next(ArrayList.java:859)
	at com.czj.example01.TestList.main(TestList.java:17)

可以看到抛出了ConcurrentModificationException异常,这是因为list的fast-fail的机制。

list源码分析

下面是ArrayList里的内部类Itr的remove()源码,可以看到在执行移除前会执行checkForComodification()方法。

   public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }

可以看到这里就是抛出ConcurrentModificationException异常的地方,那么modCount和expectedModCount分别代表什么呢?

  • modCount:ArrayList的成员变量,代表集合的修改次数,初始值为0
  • expected:Itr的成员变量,代表迭代器预期集合的修改次数,初始值等于创建itr时的修改次数,只有通过迭代器对集合进行操作,该值才会改变。

通过foreach来遍历集合,其实就是通过集合的迭代器(Iterator)来遍历的,如果不通过迭代器来修改集合内的元素,只要他发现有某一次修改是未经过自己进行的,那么就会抛出异常。

fail-safe

fail-safe字面理解***安全失败***,java.util包下面的所有的集合类都是快速失败的,而java.util.concurrent包下面的所有的类都是安全失败的。快速失败的迭代器会抛出ConcurrentModificationException异常,而安全失败的迭代器永远不会抛出这样的异常。

集合中的fail-safe
        List<Integer> list = new CopyOnWriteArrayList<Integer>(){{
            for (int i=1;i<=10;i++){
                add(i);
            }
        }};

        for (Integer integer:list){
            if (integer==5){
                list.remove(integer);
            }
            System.out.println(integer);
        }

上面使用CopyOnWriteArrayList这个类来演示fail-safe,这样的集合容器在遍历时不是直接在集合内容上访问的,而是先复制原有集合内容,在拷贝的集合上进行遍历。迭代器遍历的是开始遍历那一刻拿到的集合拷贝,在遍历期间原集合发生的修改迭代器是不知道的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值