当错误发生时,如果系统立即关闭,即是快速失败,系统不会继续运行。运行中发生错误,它会立即停止操作,错误也会立即暴露。而安全失败系统在错误发生时不会停止运行。它们隐蔽错误,继续运行,而不会暴露错误。这两种模式,孰优孰优,是系统设计中常讨论的话题。
快速失败迭代器 | 安全失败迭代器 |
---|---|
在迭代时不允许结构上的修改; 结构上的修改是指任何添加或删除一个或多个元素的操作,或者显式调整底层数组的大小; 仅仅设置元素的值不是结构上的修改 |
在迭代时允许修改集合 |
迭代时被修改抛出ConcurrentModificationException异常 | 迭代时集合被修改不抛出异常 |
使用原集合遍历集合元素 | 使用原集合的副本遍历集合元素 |
迭代器不要求额外的内存 | 迭代器需要额外的内存克隆集合对象 |
示例:ArrayList, Vector, HashMap | 示例:ConcurrentHashMap |
快速失败迭代器 :
大多数集合类返回的快速失败迭代器在遍历时不允许结构性修改(结构性修改指添加,删除和更新一个元素) 当遍历的同时被结构性修改,就会抛出ConcurrentModificationException异常,而当集合是被迭代器自带的方法(如remove())修改时,不会抛出异常。
快速失败迭代器运行原理:
所有的集合类都维护着一个对象数组(Object[]),用来存储元素, 快速失败迭代器直接从数组中获取元素,在迭代过程中,总是假定该内部数组不会被修改。为了判断这个集合是否被修改,它们使用名为modCount的内部标识,当集合被修改,该标识也会更新。迭代器每次调用next()方法,都会检查modCount,如果发现modCount被更新,就会抛出ConcurrentModificationException异常。
安全失败迭代器 :
安全失败迭代器在迭代中被修改,不会抛出任何异常,因为它是在集合的克隆对象迭代的,所以任何对原集合对象的结构性修改都会被迭代器忽略,但是这类迭代器有一些缺点,其一是它不能保证你迭代时获取的是最新数据,因为迭代器创建之后对集合的任何修改都不会在该迭代器中更新,还有一个缺点就是创建克隆对象在时间和内存上都会增加一些负担。