JavaSE---Fail-Fast

总结

  主要用于集合类中,以确保 在遍历集合时如果集合本身被修改,则会立即抛出ConcurrentModificationException异常。

原理

  • 内部计数器:每个集合对象都有一个内部计数器,称为modCount(modification count)。每当集合结构被修改(比如添加或删除元素),这个计数器就会增加。
  • 迭代器检查:当通过迭代器遍历集合时,迭代器会在每次调用next()方法之前检查当前的modCount是否与创建迭代器时的expectedModCount相匹配。如果不匹配,说明集合已经被修改了,这时迭代器就会抛出ConcurrentModificationException

 

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable {

        transient Object[] elementData;
        private int size;
        
        // add
        public boolean add(E e) {
            ensureCapacityInternal(size + 1);  // Increments modCount!!
            elementData[size++] = e;                                                        // size ++
            return true;
        }

        private void ensureCapacityInternal(int minCapacity) {
            ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
        }

        private void ensureExplicitCapacity(int minCapacity) {
            modCount++;                                                                     // modCount++

            // overflow-conscious code
            if (minCapacity - elementData.length > 0)
                grow(minCapacity);
        }

        // remove
        public boolean remove(Object o) {
            if (o == null) {
                for (int index = 0; index < size; index++)
                    if (elementData[index] == null) {
                        fastRemove(index);
                        return true;
                    }
            } else {
                for (int index = 0; index < size; index++)
                    if (o.equals(elementData[index])) {
                        fastRemove(index);
                        return true;
                    }
            }
            return false;
        }

        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; // clear to let GC do its work                  // --size
        }

        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 = 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 {
                    this.remove(lastRet);
                    cursor = lastRet;
                    lastRet = -1;
                    expectedModCount = modCount;
                } catch (IndexOutOfBoundsException ex) {
                    throw new ConcurrentModificationException();
                }
            }

            final void checkForComodification() {
                if (modCount != expectedModCount)                       // modCount与expectedModCount比较
                    throw new ConcurrentModificationException();
            }
        }
    }

  

示例

单线程

  当使用iterator遍历List & 使用List的remove,将会ConcurrentModificationException;

List<String> list = new ArrayList<>();
        list.add("Apple");
        list.add("Banana");
        list.add("Cherry");
        list.add("Banana");
        
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            String fruit = iterator.next();
            // 在遍历过程中修改集合
            if ("Banana".equals(fruit)) {
                list.remove(fruit);
            }
        }
        System.out.println(list);

  list的remove会修改modCount,导致modCount 与 expectedModCount不相等;

 

解决  

1、使用iterator遍历时,使用iterator的remove,将不会修改modCount;

2、多线程环境,使用线程安全集合类;

3、同步控制,保证只有一个线程能访问集合;

posted on 2024-09-23 16:11  anpeiyong  阅读(6)  评论(0编辑  收藏  举报

导航