fail-fast機制
- java集合(Collection)中的一種錯誤機制
- 當多個線程對同一個集合的內容進行操作時,就可能產生fail-fast事件
- 只能用來檢測錯誤
- 測試代碼
public class Test { private static List<String> list = new ArrayList<>(); /** * @Description: 打印list內容 */ public static void showAll(){ System.out.println("\nnum is "); String num = null; Iterator iterator = list.iterator(); while(iterator.hasNext()){ num = (String) iterator.next(); System.out.print(num + " "); } } /** * @Description: 往list中添加數據,並打印list中數據 */ public static class ThreadOne extends Thread{ public void run(){ int index = 0; while(index < 10){ list.add(String.valueOf(index)); showAll(); ++index; } } } public static class ThreadTwo extends Thread{ public void run(){ int index = 10; while(index < 20){ list.add(String.valueOf(index)); showAll(); ++index; } } } public static void main(String[] args) { // 同時啓動兩個線程操作list new ThreadOne().start(); new ThreadTwo().start(); } }
- 運行代碼。拋出異常java.util.ConcurrentModificationException,即fail-fast事件
- 若想在多線程環境下使用fail-fast機制的集合
// 原代碼 private static List<String> list = new ArrayList<String>(); // 修改爲 private static List<String> list = new CopyOnWriteArrayList<String>();
- fail-fast原理
- ArrayList的Iterator是在父類AbstractList.java中實現
package java.util; public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> { /** * 部分源碼 */ // 記錄List修改的次數:每一次添加/刪除等操作,將modCount+1 protected transient int modCount = 0; // 返回List對應迭代器。實際上,是返回Itr對象。 public Iterator<E> iterator() { return new Itr(); } // Itr是Iterator(迭代器)的實現類 private class Itr implements Iterator<E> { int cursor = 0; int lastRet = -1; // 修改數的記錄值。 // 每次新建Itr()對象時,都會保存新建該對象時對應的modCount; // 以後每次遍歷List中的元素的時候,都會比較expectedModCount和modCount是否相等 // 若不相等,則拋出ConcurrentModificationException異常,產生fail-fast事件 int expectedModCount = modCount; public boolean hasNext() { return cursor != size(); } public E next() { // 獲取下一個元素之前,都會判斷“新建Itr對象時保存的modCount”和“當前的modCount”是否相等; // 若不相等,則拋出ConcurrentModificationException異常,產生fail-fast事件。 checkForComodification(); try { E next = get(cursor); lastRet = cursor++; return next; } catch (IndexOutOfBoundsException e) { checkForComodification(); throw new NoSuchElementException(); } } public void remove() { if (lastRet == -1) throw new IllegalStateException(); checkForComodification(); try { AbstractList.this.remove(lastRet); if (lastRet < cursor) cursor--; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException e) { throw new ConcurrentModificationException(); } } final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } } }
- ArrayList源碼,modCount被修改
package java.util; public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { /** * 部分源碼 */ // list中容量變化時,對應的同步函數 public void ensureCapacity(int minCapacity) { modCount++; int oldCapacity = elementData.length; if (minCapacity > oldCapacity) { Object oldData[] = elementData; int newCapacity = (oldCapacity * 3)/2 + 1; if (newCapacity < minCapacity) newCapacity = minCapacity; // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); } } // 添加元素到隊列最後 public boolean add(E e) { // 修改modCount ensureCapacity(size + 1); // Increments modCount!! elementData[size++] = e; return true; } // 添加元素到指定的位置 public void add(int index, E element) { if (index > size || index < 0) throw new IndexOutOfBoundsException( "Index: "+index+", Size: "+size); // 修改modCount ensureCapacity(size+1); // Increments modCount!! System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; } // 添加集合 public boolean addAll(Collection<? extends E> c) { Object[] a = c.toArray(); int numNew = a.length; // 修改modCount ensureCapacity(size + numNew); // Increments modCount System.arraycopy(a, 0, elementData, size, numNew); size += numNew; return numNew != 0; } // 刪除指定位置的元素 public E remove(int index) { RangeCheck(index); // 修改modCount modCount++; E oldValue = (E) elementData[index]; int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // Let gc do its work return oldValue; } // 快速刪除指定位置的元素 private void fastRemove(int index) { // 修改modCount modCount++; int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // Let gc do its work } // 清空集合 public void clear() { // 修改modCount modCount++; // Let gc do its work for (int i = 0; i < size; i++) elementData[i] = null; size = 0; } }
- 可以發現涉及到修改集合中的元素個數時,都會改變modCount的值
- ArrayList的Iterator是在父類AbstractList.java中實現