fail-fast(快速失败)
fail-safe(安全失败)
一、快速失败(fail-fast)
每个实现了Collection接口的集合类都有一个iterator()方法,该方法返回一个 Iterator对象(这是一种迭代器的设计模式),在Iterator对象中进行 遍历(next),删除(remove)操作的时候,可能会发生ConcurrentModificationException 异常 。(所以要理解不是在ArrayList中进行遍历,删除(remove)操作的时候发生ConcurrentModificationException 异常)。
Iterator迭代器对象的 next()、remove()方法中都调用checkForComodification()方法,
进行 modCount != expectedModCount 判断,不一致就发生ConcurrentModificationException 异常。 这就是 fail-fast 机制 !!他的原理就是在迭代器中遍历数据的时候,如果集合同时进行了添加元素(add操作) ,删除元素(remove操作) ,例如被另外一个线程操作了,就会发生 类似 ‘脏数据’的问题,就会通过抛出异常的是否来告知用户。
二、安全失败(fail-safe)
实际应用中,同一个集合可能被多个线程访问操作,线程1遍历的时候,线程2对集合进行了添加删除操作,如果经常发生ConcurrentModificationException 异常,那好像没法玩了这个程序,所以聪明的人的解决办法就是,每次添加删除元素的时候,对原集合进行一次copy,在新copy出来的集合上进行 添加删除元素,而遍历访问还是原来 的old 集合上。这样就不会发生Iterator 遍历时出现异常。 这就是 fail-safe 机制!!
貌似java.util.concurrent包下的容器都是 fail-safe安全失败,可以在多线程下并发使用,并发修改。例如:
CopyOnWriteArrayList CopyOnWriteArraySet
三、jdk作者为什么这么设计呢?
就是jdk作者为什么要设计 针对不同的容器,有的是fail-fast,有的是fail-safe
我的理解是这样的,容器就相当于数据库,容器中的元素就是数据了,为了保证同一个线程迭代器遍历集合的时候,遍历前后数据一致性(访问的集合元素是一致的,没有发生变化),如果发生了变化就直接抛出异常,快速失败fail-fast机制,通过显示的抛出异常告诉调用者,让调用者知道遍历集合时,同时集合元素发生了变化。调用者自己来决定如何处理。否则调用者遍历到了元素,但是立刻又被其他线程把该元素删除了,不在集合容器中了,导致调用者还在对该元素进行一系列的操作,但是却不是集合中的元素了。白白的操作,错误的操作,调用者还不知晓。
当然调用者也可以catch ConcurrentModificationException 异常,进行异常处理,或者不处理都是可以的 ,看自己的需要。