synchronized 是java中常見的保證多線程訪問共用資源時的安全的一個關鍵字。很多人在講到synchronized 時都說synchronized 是一把重量級的鎖,那麼synchronized 真的很重麽? synchronized 在jdk 1.6以前(不包括1.6)的確是一把很重的鎖 ...
轉自:
http://www.java265.com/JavaJingYan/202206/16540696313601.html
下文筆者講述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 |