關於 java.util.ConcurrentModificationException jdk源碼分析

先看怎麼發生java

List<Integer> list=new ArrayList<>();
for(int i=0;i<10;i++){
    list.add(i);
}
Iterator<Integer> it=list.iterator();
while(it.hasNext()){
    Integer str=it.next();
    if(str==5)
    list.remove(str);//不經過it.remove()方法刪除,而是經過list.remove()方法刪除元素
}

這段代碼,就會發生java.util.ConcurrentModificationException異常
一下看看實現:
先看 AbstractList 類有這樣一個變量安全

/**
     * The number of times this list has been <i>structurally modified</i>.
     * Structural modifications are those that change the size of the
     * list, or otherwise perturb it in such a fashion that iterations in
     * progress may yield incorrect results.
     *  他表明list被修改的次數(通常指 add,remove 次數。某個元素重賦值,通常不計數 )
     * <p>This field is used by the iterator and list iterator implementation
     * returned by the {@code iterator} and {@code listIterator} methods.
     * If the value of this field changes unexpectedly, the iterator (or list
     * iterator) will throw a {@code ConcurrentModificationException} in
     * response to the {@code next}, {@code remove}, {@code previous},
     * {@code set} or {@code add} operations.  This provides
     * <i>fail-fast</i> behavior, rather than non-deterministic behavior in
     * the face of concurrent modification during iteration.
     *  這個變量,通常在是  iterator , list iterator 實現時用到的,而且在他們的 next,remove,add,previous 等方法中,會利用它決定是否拋出ConcurrentModificationException異常。
     * <p><b>Use of this field by subclasses is optional.</b> If a subclass
     * wishes to provide fail-fast iterators (and list iterators), then it
     * merely has to increment this field in its {@code add(int, E)} and
     * {@code remove(int)} methods (and any other methods that it overrides
     * that result in structural modifications to the list).  A single call to
     * {@code add(int, E)} or {@code remove(int)} must add no more than
     * one to this field, or the iterators (and list iterators) will throw
     * bogus {@code ConcurrentModificationExceptions}.  If an implementation
     * does not wish to provide fail-fast iterators, this field may be
     * ignored.
     * 也能夠在子類中利用這個字段,提供快速失敗機制。具體在像add,remove方法中,增長modCount的值,每次調用加1。而後利用它,決定是否拋出ConcurrentModificationExceptions
     */
    protected transient int modCount = 0;

接着看ArrayList類方法多線程

/**
     * Returns an iterator over the elements in this list in proper sequence.
     * 這個方法,返回一個自己list的一個iterator
     * <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
     *
     * @return an iterator over the elements in this list in proper sequence
     */
    public Iterator<E> iterator() {
        return new Itr();//關鍵這個類
    }

再看 Itr類ide

/**
     * An optimized version of AbstractList.Itr
     */
    private class Itr implements Iterator<E> {
        int cursor;       // index of next element to return  //有個潛臺詞,默認值是0,list當前的下標
        int lastRet = -1; // index of last element returned; -1 if no such
        int expectedModCount = modCount;//初始化時候,會把list原來的修改次數,賦給expectedModCount

        public boolean hasNext() {
            return cursor != size;
        }

        @SuppressWarnings("unchecked")
        public E next() {
            checkForComodification();//會拋出java.util.ConcurrentModificationException異常
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;//每次,移動下標加1,下次的遊標位置
            return (E) elementData[lastRet = i];//lastRet 賦值本次的座標。
        }

        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();//會拋出java.util.ConcurrentModificationException異常

            try {
                ArrayList.this.remove(lastRet);//根據下標刪除元素,ArrayList.this.remove()方法,會modCount++;
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;//讓後又把最新的modCount 賦給expectedModCount,這樣保證,經過Itr remove方法刪除元素,不會拋ConcurrentModificationException異常,由於expectedModCount == modCount
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        final void checkForComodification() {//拋出java.util.ConcurrentModificationException異常的方法
            if (modCount != expectedModCount)//若是modCount 不等於expectedModCount 就拋出這個異常
                throw new ConcurrentModificationException();
        }
    }

最後,再回來講ConcurrentModificationException異常,直接一點,它的做用是,一個集合(list 實現,好比ArrayList,LinkedList,Vertor 等AbstractList子類),
在用它本身的Iterator對象 在玩轉它自己時(next,remove,add,previous 調用)時,若是發現有其餘方式(非這個Iterator 對象),
修改這個list對象,就會(經過比較modCount, expectedModCount值)拋出ConcurrentModificationException異常。因爲 Iterator 對象不是線程安全的,在多線程中用it.remove()刪除元素,一樣能夠拋出 ConcurrentModificationException異常 !this

相關文章
相關標籤/搜索