Java List Iterator ConcurrentModificationException异常原因

异常原因

package com.company;
 
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
 
/**
 * @Author you guess
 * @Date 2021/1/7 12:33
 * @Version 1.0
 * @Desc
 */
public class Main26 {
 
 
    public static void main(String[] args) {
        List<String> res1 = new ArrayList<>();
        res1.add("1");
        res1.add("2");
        res1.add("3");
        res1.add("4");
//        res1.add("5");
//        res1.add("6");
//        res1.add("7");
//        res1.add("8");
//        res1.add("9");
 
        System.out.println(res1);//[1, 2, 3, 4]
 
        //死循环
//        for (int i = 0; i < res1.size(); i++) {
//            res1.add(i + 10 + "");
//        }
 
 
//
//        int size = res1.size();
//        for (int i = 0; i < size; i++) {
//            res1.add(i + 10 + "");
//        }
//        System.out.println(res1);//[1, 2, 3, 4, 10, 11, 12, 13]
 
 
//        for (int i = 0; i < res1.size(); i++) {
//            res1.remove(i);
//        }
//        System.out.println(res1);//[2, 4]
 
 
//        for (int i = 0; i < res1.size(); i++) {
//            if (res1.get(i).equals("1")) {
//                res1.remove(i);
//            }
//        }
//        System.out.println(res1);//[2, 3, 4]
 
 
        Iterator<String> iterator = res1.iterator();
        while (iterator.hasNext()) {//ArrayList.Itr.hasNext()
            String str = iterator.next();//ArrayList.Itr.next()
            if (str.equals("2"))
//                res1.remove(str);//ArrayList.remove();Exception in thread "main" java.util.ConcurrentModificationException
                iterator.remove();//正常,ArrayList.Itr.remove(),原list的该元素也会删掉
        }
        System.out.println(res1);//[1, 3, 4]
    }
}
复制代码

为何会报异常ConcurrentModificationException?

上述代码只有res1.remove()才是调用的ArrayList自身的代码,res1.remove()执行时会导致modCount加1,但是expectedModCount却没有变化,等到执行iterator.next()时会导致异常!!

如果用iterator.remove()则不报异常!!

ArrayList.java某段:Iterator的方法源码:

    /**
     * An optimized version of AbstractList.Itr
     */
    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;//expectedModCount是在Itr中定义的
 
        Itr() {}
 
        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();
            }
        }
 
        @Override
        @SuppressWarnings("unchecked")
        public void forEachRemaining(Consumer<? super E> consumer) {
            .......
        }
 
        final void checkForComodification() {//抛出异常
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }
复制代码

ArrayList.java某段:自身的方法源码

    /**
     * Removes the element at the specified position in this list.
     * Shifts any subsequent elements to the left (subtracts one from their
     * indices).
     *
     * @param index the index of the element to be removed
     * @return the element that was removed from the list
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public E remove(int index) {
        rangeCheck(index);
 
        modCount++;//加1,expectedModCount是在Itr中定义的,没有赋值给expectedModCount
        E oldValue = elementData(index);
 
        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
 
        return oldValue;
    }
 
    /**
     * Removes the first occurrence of the specified element from this list,
     * if it is present.  If the list does not contain the element, it is
     * unchanged.  More formally, removes the element with the lowest index
     * <tt>i</tt> such that
     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>
     * (if such an element exists).  Returns <tt>true</tt> if this list
     * contained the specified element (or equivalently, if this list
     * changed as a result of the call).
     *
     * @param o element to be removed from this list, if present
     * @return <tt>true</tt> if this list contained the specified element
     */
    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 remove method that skips bounds checking and does not
     * return the value removed.
     */
    private void fastRemove(int index) {
        modCount++;//加1,expectedModCount是在Itr中定义的,没有赋值给expectedModCount
        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
    }
复制代码

jdk1.8源码  如上。

方法:单线程,使用 iterator.remove();即可,原list的该元素也会删掉

方法:多线程,CopyOnWriteArrayList(不保证数据一致性)

    /**
     * 原因在于,虽然Vector的方法采用了synchronized进行了同步,但是实际上通过Iterator访问的情况下,每个线程里面返回的是不同的iterator,
     * 也即是说expectedModCount是每个线程私有。假若此时有2个线程,线程1在进行遍历,线程2在进行修改,那么很有可能导致线程2修改后导致Vector中的modCount自增了,
     * 线程2的expectedModCount也自增了,但是线程1的expectedModCount没有自增,此时线程1遍历时就会出现expectedModCount不等于modCount的情况了。
     * <p>
     * expectedModCount是线程私有的,modCount是线程共享的;
     * thread2使expectedModCount、modCount都加1后,但是thread1的modCount还是原值,所以抛出异常
     *
     * @param args
     */
    public static void main(String[] args) {
        //Vector<Integer> list = new Vector<Integer>(); 也报异常ConcurrentModificationException
        ArrayList<Integer> list = new ArrayList<Integer>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        Thread thread1 = new Thread() {
            public void run() {
                Iterator<Integer> iterator = list.iterator();
                while (iterator.hasNext()) {
                    Integer integer = iterator.next();
                    System.out.println(integer);
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
 
            ;
        };
        Thread thread2 = new Thread() {
            public void run() {
                Iterator<Integer> iterator = list.iterator();
                while (iterator.hasNext()) {
                    Integer integer = iterator.next();
                    if (integer == 2)
                        iterator.remove();
                }
            }
 
            ;
        };
        thread1.start();
        thread2.start();
    }
//    1
//    Exception in thread "Thread-0" java.util.ConcurrentModificationException
//    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
//    at java.util.ArrayList$Itr.next(ArrayList.java:859)
//    at com.company.Main27$1.run(Main27.java:25)
 
 
 
    public static void main(String[] args) {
        CopyOnWriteArrayList<Integer> list = new CopyOnWriteArrayList<Integer>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        Thread thread1 = new Thread() {
            public void run() {
                Iterator<Integer> iterator = list.iterator();
                while (iterator.hasNext()) {
                    Integer integer = iterator.next();
                    System.out.println(integer);
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
 
            ;
        };
        Thread thread2 = new Thread() {
            public void run() {
                Iterator<Integer> iterator = list.iterator();
                while (iterator.hasNext()) {
                    Integer integer = iterator.next();
                    if (integer == 2)
                        iterator.remove();
                }
            }
 
            ;
        };
        thread1.start();
        thread2.start();
    }
//    Exception in thread "Thread-1" java.lang.UnsupportedOperationException
//    at java.util.concurrent.CopyOnWriteArrayList$COWIterator.remove(CopyOnWriteArrayList.java:1178)
//    at com.company.Main27$2.run(Main27.java:92)
//    1
//    2
//    3
//    4
//    5
复制代码

end

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享