java中fail-fast和fail-safe的区别说明
下文笔者讲述fail-fast和fail-safe的区别说明,如下所示
同步修改简介说明
同步修改(并发修改)指: 当一个或多个线程正在遍历一个集合Collection 此时另一个线程修改了这个集合的内容(添加,删除或修改)
fail-fast机制
fail-fast机制: 在遍历一个集合时,当集合结构被修改,会抛出Concurrent Modification Exception fail-fast: 会在以下两种情况下抛出ConcurrentModificationException 1.单线程环境 集合被创建后,在遍历它的过程中修改了结构。 注意: remove()方法会让expectModcount和modcount相等,所以是不会抛出这个异常 2.多线程环境 当一个线程在遍历这个集合,而另一个线程对这个集合的结构进行了修改 注意事项: 迭代器的快速失败行为无法得到保证, 因为一般来说,不可能对是否出现不同步并发修改做出任何硬性保证 快速失败迭代器会尽最大努力抛出 ConcurrentModificationException 因此,为提高这类迭代器的正确性而编写一个依赖于此异常的程序是错误的做法:迭代器的快速失败行为应该仅用于检测bug
fail-fast机制检测方法分享
迭代器在遍历过程中是直接访问内部数据的 因此内部的数据在遍历的过程中无法被修改 为了保证不被修改,迭代器内部维护了一个标记"mode", 当集合结构改变(添加删除或者修改) 标记"mode"会被修改,而迭代器每次的hasNext()和next()方法都会检查该"mode"是否被改变 当检测到被修改时,抛出Concurrent Modification Exception 下面看看Arraylist迭代器部分的源码 private class Itr implements Iterator<E> { int cursor; int lastRet = -1; int expectedModCount = ArrayList.this.modCount; public boolean hasNext() { return (this.cursor != ArrayList.this.size); } public E next() { checkForComodification(); /** 省略此处代码 */ } public void remove() { if (this.lastRet < 0) throw new IllegalStateException(); checkForComodification(); /** 省略此处代码 */ } final void checkForComodification() { if (ArrayList.this.modCount == this.expectedModCount) return; throw new ConcurrentModificationException(); } }
fail-safe机制
fail-safe任何对集合结构的修改都会在一个复制的集合上进行修改,因此不会抛出ConcurrentModificationException fail-safe机制有两个问题 1.需要复制集合,产生大量的无效对象,开销大 2.无法保证读取的数据是目前原始数据结构中的数据
fail-fast和fail-safe示例
import java.util.HashMap; import java.util.Iterator; import java.util.Map; public class FailFastExample { public static void main(String[] args) { Map<String,String> map = new HashMap<String,String>(); map.put("test", "test"); map.put("test2", "test2"); map.put("test3","test3"); Iterator iterator = map.keySet().iterator(); while (iterator.hasNext()) { System.out.println(map.get(iterator.next())); map.put("test5", "test555"); } } } -----运行以上代码,将输出以下信息----- Exception in thread "main" java.util.ConcurrentModificationException at java.util.HashMap$HashIterator.nextEntry(Unknown Source) at java.util.HashMap$KeyIterator.next(Unknown Source) at FailFastExample.main(FailFastExample.java:20) import java.util.concurrent.ConcurrentHashMap; import java.util.Iterator; public class FailSafeExample { public static void main(String[] args) { ConcurrentHashMap<String,String> map = new ConcurrentHashMap<String,String>(); map.put("test", "test"); map.put("test2", "test2"); map.put("test3","test3"); Iterator iterator = map.keySet().iterator(); while (iterator.hasNext()) { System.out.println(map.get(iterator.next())); map.put("test5", "test5555"); } } } 输出 test test2 test3
fail-fast和fail-safe的区别
Fail Fast Iterator | Fail Safe Iterator | |
Throw ConcurrentModification Exception | yes | no |
Clone object | no | yes |
Memory Overhead | no | yes |
例 | HashMap,Vector,ArrayList,HashSet | CopyOnWriteArrayList, ConcurrentHashMap |
版权声明
本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。