什么是fail-fast机制,怎样避免fail-fast机制?


什么是fail-fast机制,怎样避免fail-fast机制?

什么是fail-fast机制

如果我们对一个集合进行遍历,而在集合遍历的过程中对其进行修改(增加、删除、修改)

或者 一个线程在对结合进行过遍历,另外一个线程对其修改,则会报ConcurrentModificationException 异常。

举例说明fail-fast 机制

  1. 场景: 单线程环境下,遍历的时候,进行删除
什么是fail-fast机制,怎样避免fail-fast机制?

测试结果如下:


什么是fail-fast机制,怎样避免fail-fast机制?

2、场景2: 多线程环境下,一个对集合进行遍历元素。一个对集合删除元素

什么是fail-fast机制,怎样避免fail-fast机制?

测试结果:


什么是fail-fast机制,怎样避免fail-fast机制?

3、场景3-对ArrayList 的subList进行操作

参考如下:

fail-fast 机制 为什么会出现ConcurrentModificationException异常

我们先看下Iterator 类:

1、ArrayList 的add、set 等操作都会进行modCount++;

什么是fail-fast机制,怎样避免fail-fast机制?

什么是fail-fast机制,怎样避免fail-fast机制?

2、调用list.iterator时会new Itr();

创建Itr的过程,保存了 ArrayList中的modeCount,每次进行遍历list的时候都会调用

checkForComodification方法:


什么是fail-fast机制,怎样避免fail-fast机制?

上面检查 expectedModCount和modCount是否相等,若不相等,则抛出异常

所以说在循环的时候对list进行remove, expectedModCount和modCoun不相等,所以会报异常(场景1),

3、为什么多线程场景下也会出现ConcurrentModificationException 异常

上面的场景2,两个线程初始化时,都持有list的modCount,当一个线程在遍历,一个线程在删除,

也会导致 expectedModCount和modCoun不相等。


怎么解决fail-fast 出现的异常


1、在单线程环境下,我们可以不调用集合的remove方法,可以调用 Iterator的remove方法。


什么是fail-fast机制,怎样避免fail-fast机制?

为什么可以调用 Iterator 的remove方法呢?


什么是fail-fast机制,怎样避免fail-fast机制?

从上面源码可以看出,每次remove并不会修改modCount值,因为 每次remove只remove遍历过的元素,所以不会发生fail-fast。


2、在多线程环境下,使用concurrent下的并发类

比如: 我们使用CopyOnArrayList 来代替 ArrayList,用ConcurrentHashMap 代理 HashMap

CopyOnArrayList参考下面文章。


什么是fail-fast机制,怎样避免fail-fast机制?

使用 CopyOnArrayList 需要注意一下事项:

  • 初始化 设置合理的初始如果能量,因为扩容的代价非常大
  • 使用批量的添加(addAll)或者批量删除(removeAll)操作,这个可以避免每次添加都会元素
  • CopyOnArrayList只能保证最终一致性,不能保证每次读取都是最新数据


总结

1、java.util 下的所有集合类都是fail-fast

2、concurrent 下的所有集合类都是fail-safe

3、在多线程环境下,尽量使用 concurrent 下的集合类


分享到:


相關文章: