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中实现