您的位置:首页 > Web前端

fail-fast和fail-safe详解

2017-08-21 23:43 330 查看

简介

fail-fast(快速失败)是Java对java.util包下的所有集合类的是一种错误检测机制。

fail-safe(安全失败)采用安全失败机制的集合容器,在遍历时不是直接在集合内容上访问的,而是先复制原有集合内容,在拷贝的集合上进行遍历。

区别

java.util包下面的所有的集合类都是快速失败的,而java.util.concurrent包下面的所有的类都是安全失败的。fail-fast(快速失败)的迭代器会抛出ConcurrentModificationException异常,而因为安全失败是基于对底层集合做拷贝,所以,它不受源集合上修改的影响,安全失败的迭代器永远不会抛出这样的异常。

fail-fast触发方式

首先是触发场景,若触发了快速失败,其场景一定是多线程同事操作一个集合类。以ArrayList来说,通过查看源码得知:在ArrayList中的Iterator(继承父类AbstractList中的Iterator)中发现,当对ArrayList进行迭代时,当调用next()和remove()方法时,会去调用检查方法checkForComodification()去检查是否要抛出ConcurrentModificationException异常。

注意:这里异常的抛出条件是检测到 modCount!=expectedmodCount 这个条件。如果集合发生变化时修改modCount值刚好又设置为了expectedmodCount值,则异常不会抛出。因此,不能依赖于这个异常是否抛出而进行并发操作的编程,这个异常只建议用于检测并发修改的bug。

具体检查方法:在说具体方法前,先要理解两个变量modCount 和expectedModCount。expectedModCount 当迭代器创建时创建并且赋值为modCount ,并且expectedModCount 不可以被修改,而modCount 当ArrayList每被结构上修改一次modCount ++,随意只要判断expectedModCount 和modCount 两个变量是否一致即可决定是否抛出异常。

所谓结构被修改指的是,当对集合进行add(), remove() 或clear() 操作时,即改变集合的长度时(我是这么理解的-.-)就会改变集合的结构。在这里需要注意一点:当该变集合中元素的取值时,这不是改变集合的结构。

fail-fast解决方法

可以使用java.util.concurrent包中的集合类进行操作。如需要一个ArrayList时可以使用java.util.concurrent中对应的CopyOnWriteArrayList类进行操作。CopyOnWriteArrayList和ArrayList所实现有所不同,CopyOnWriteArrayList没有继承于AbstractList,它仅仅只是实现了List接口。

fail-safe

原理:由于迭代时是对原集合的拷贝进行遍历,所以在遍历过程中对原集合所作的修改并不能被迭代器检测到,所以不会触发Concurrent Modification Exception。

缺点:基于拷贝内容的优点是避免了Concurrent Modification Exception,但同样地,迭代器并不能访问到修改后的内容,即:迭代器遍历的是开始遍历那一刻拿到的集合拷贝,在遍历期间原集合发生的修改迭代器是不知道的。

场景:java.util.concurrent包下的容器都是安全失败,可以在多线程下并发使用,并发修改。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: