美文网首页
fail-fast 和 fail-safe

fail-fast 和 fail-safe

作者: markeNick | 来源:发表于2020-04-17 22:45 被阅读0次

    什么是并发修改


    当一个或多个线程正在遍历一个集合(Collection),此时另一个线程修改了这个集合(添加,删除或修改)就称为并发修改。

    .

    fail-fast(快速失败机制)


    官方文档在HashMap集合中对fail-fast的解释

    官方文档对fail-fast的解释

    意思就是:这个迭代器(Iterator)被创建后,除了迭代器自身的方法(remove)可以改变集合的结构,其他情况改变了集合的结构,都将跑出一个ConcurrentModificationException异常。

    改变集合结构才会导致 fail-fast,修改集合元素并不会

    分析ArrayList源码:
    ArrayList部分源码

    从上面的源码,可以发现迭代器在执行next()等方法的时候,都会调用一个方法checkForComodification(),而这个方法就是检查 modCount 是否等于 expectedModCount,如果不等于就抛出ConcurrentModificationException异常。

    expectedModCount 这个变量的值在对象被创建的时候就赋予了一个固定的值 modCount ,这个值是不变的,当迭代器遍历元素的时候,如果 modCount 发生了改变,那就会抛出异常。

    查看源码可以发现,当对集合进行增删操作都会 modCount++

    所以当我们对集合的元素的个数做出修改(添加、删除)的时候,modCount 的值就会发生改变,但对元素进行修改则不会改变 modCount 的值。

    如何预防因为 fail-fast 而抛出异常

    保证在并发修改的时候,对所有会影响到 modCount 发生改变的地方,加上同步锁(synchronized),或者使用同步类容器 Collections.synchronizedList

    .

    fail-safe(安全失败机制)


    fail-safe:任何对集合结构的修改都会在一个复制的集合上进行修改,因此不会抛出ConcurrentModificationException异常。

    两个问题:

    • 开销大,因为需要复制集合,产生大量的无效对象
    • 无法保证读取的数据是目前原始数据结构中的数据
    分析CopyOnWriteArrayList源码
    CopyOnWriteArrayList部分源码

    从源码可以看到,在对集合进行添加和删除元素的时候都进行加锁,然后让当前下标的元素添加或删除,最后将原数组的地址指向新的数组,完成复制。这里涉及到CopyOnWrite机制

    这样做不会出现 fail-fast ,但是对集合进行增删操作都需要加锁,影响效率。同时增加对象容量可能会导致 OOM

    在遍历过程中,集合的元素并不一定是最终的元素集合,所以只能保证最终一致性。

    相关文章

      网友评论

          本文标题:fail-fast 和 fail-safe

          本文链接:https://www.haomeiwen.com/subject/yeqpvhtx.html