標籤:out 派生 source pop last static 遍曆 rem strong
原文地址:http://javahungry.blogspot.com/2014/04/fail-fast-iterator-vs-fail-safe-iterator-difference-with-example-in-Java.html
在我們詳細討論這兩種機制的區別之前,首先得先瞭解並發修改。
1.什麼是同步修改?
當一個或多個線程正在遍曆一個集合Collection,此時另一個線程修改了這個集合的內容(添加,刪除或者修改)。這就是並發修改
2.什麼是 fail-fast 機制?
fail-fast機制在遍曆一個集合時,當集合結構被修改,會拋出Concurrent Modification Exception。
fail-fast會在以下兩種情況下拋出ConcurrentModificationException
(1)單線程環境
集合被建立後,在遍曆它的過程中修改了結構。
注意 remove()方法會讓expectModcount和modcount 相等,所以是不會拋出這個異常。
(2)多線程環境
當一個線程在遍曆這個集合,而另一個線程對這個集合的結構進行了修改。
注意,迭代器的快速失敗行為無法得到保證,因為一般來說,不可能對是否出現不同步並發修改做出任何硬性保證。快速失敗迭代器會盡最大努力拋出 ConcurrentModificationException。因此,為提高這類迭代器的正確性而編寫一個依賴於此異常的程式是錯誤的做法:迭代器的快速失敗行為應該僅用於檢測 bug。
3. fail-fast機制是如何檢測的?
迭代器在遍曆過程中是直接存取內部資料的,因此內部的資料在遍曆的過程中無法被修改。為了保證不被修改,迭代器內部維護了一個標記 “mode” ,當集合結構改變(添加刪除或者修改),標記"mode"會被修改,而迭代器每次的hasNext()和next()方法都會檢查該"mode"是否被改變,當檢測到被修改時,拋出Concurrent Modification Exception
。下面看看ArrayList迭代器部分的源碼
[java] view plain copy
- 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();
- }
- }
可以看到它的標記“mode”為 expectedModeCount
4. fail-safe機制
fail-safe任何對集合結構的修改都會在一個複製的集合上進行修改,因此不會拋出ConcurrentModificationException
fail-safe機制有兩個問題
(1)需要複製集合,產生大量的無效對象,開銷大
(2)無法保證讀取的資料是目前未經處理資料結構中的資料。
5 fail-fast 和 fail-safe的例子
[java] view plain copy
- import java.util.HashMap;
- import java.util.Iterator;
- import java.util.Map;
-
- public class FailFastExample
- {
-
-
- public static void main(String[] args)
- {
- Map<String,String> premiumPhone = new HashMap<String,String>();
- premiumPhone.put("Apple", "iPhone");
- premiumPhone.put("HTC", "HTC one");
- premiumPhone.put("Samsung","S5");
-
- Iterator iterator = premiumPhone.keySet().iterator();
-
- while (iterator.hasNext())
- {
- System.out.println(premiumPhone.get(iterator.next()));
- premiumPhone.put("Sony", "Xperia Z");
- }
-
- }
-
- }
輸出
iPhone
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)
[java] view plain copy
- import java.util.concurrent.ConcurrentHashMap;
- import java.util.Iterator;
-
-
- public class FailSafeExample
- {
-
-
- public static void main(String[] args)
- {
- ConcurrentHashMap<String,String> premiumPhone =
- new ConcurrentHashMap<String,String>();
- premiumPhone.put("Apple", "iPhone");
- premiumPhone.put("HTC", "HTC one");
- premiumPhone.put("Samsung","S5");
-
- Iterator iterator = premiumPhone.keySet().iterator();
-
- while (iterator.hasNext())
- {
- System.out.println(premiumPhone.get(iterator.next()));
- premiumPhone.put("Sony", "Xperia Z");
- }
-
- }
-
- }
輸出
S5HTC oneiPhone
6. fail-fast和 fail-safe 的區別
|
Fail Fast Iterator |
Fail Safe Iterator |
Throw ConcurrentModification Exception |
Yes |
No |
Clone object |
No |
Yes |
Memory Overhead |
No |
Yes |
Examples |
HashMap,Vector,ArrayList,HashSet |
CopyOnWriteArrayList, ConcurrentHashMap
|
java中fail-fast 和 fail-safe的區別