首先要弄明白同步修改的概念,指的是一個或者多個線程正在遍歷一個集合,此時另外一個線程修改了Collection的數據結構(添加,刪除或者修改);java
1.fail-fast機制spring
fail-fast機制在集合被遍歷時,若是集合元素被修改,直接拋出Concurrent Modification Exception,有兩種狀況;springboot
1>單線程環境下數據結構
集合被建立後,在遍歷它的過程當中修改告終構。注意 remove()方法會讓expectModcount和modcount 相等,因此是不會拋出這個異常。多線程
2>多線程環境下this
一個線程在遍歷元素時,另外一個線程對元素進行了修改線程
fail-fast機制校驗的原理是內部維護了一個標識「mode」,當集合數據結構被修改時,修改mode;在每次遍歷的next和hasNext方法會去檢驗「mode」是否被修改,若修改則拋出Concurrent Modification Exceptioncode
例如ArrayList迭代部分的源碼對象
private class Itr implements Iterator<E> { int cursor; // index of next element to return int lastRet = -1; // index of last element returned; -1 if no such int expectedModCount = modCount; public boolean hasNext() { return cursor != size; } @SuppressWarnings("unchecked") public E next() { checkForComodification(); int i = cursor; if (i >= size) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i + 1; return (E) elementData[lastRet = i]; } public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { ArrayList.this.remove(lastRet); cursor = lastRet; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } }
2.fail-safe機制element
fail-safe機制在每次對集合進行修改時會複製一個新的對象,所以不會拋出ConcurrentModificationException,
fail-safe機制有兩個問題
(1)須要複製集合,產生大量的無效對象,開銷大
(2)沒法保證讀取的數據是目前原始數據結構中的數據。
3.fail-fast和fail-safe機制例子
package com.example.springbootDemo.service; 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"); } } }
package com.example.springbootDemo.service; import java.util.Iterator; import java.util.concurrent.ConcurrentHashMap; 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"); } System.out.printf("premiumPhone:"+premiumPhone.toString()); } }