首先要弄明白同步修改的概念,指的是一个或者多个线程正在遍历一个集合,此时另外一个线程修改了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()); } }