专栏首页wannshan(javaer,RPC)关于 java.util.ConcurrentModificationException jdk源码分析

关于 java.util.ConcurrentModificationException jdk源码分析

先看怎么发生

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类

 /**
     * 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异常 !

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • dubbo SPI机制源码分析

    什么是微内核?还是开闭原则的应用。把核心流程架构固定,但流程各个节点对重新改进是开放的,也可以说是面下接口编程。具体实现方法就是SPI(servicer pro...

    技术蓝海
  • dubbo集群容错策略的代码分析3

    接上篇 https://cloud.tencent.com/developer/article/1109591 dubbo 版本2.5.3 通过代码可以看到fa...

    技术蓝海
  • Java 多线程协调工具 CyclicBarrier 与CountDownLatch 学习

    CyclicBarrier import java.util.concurrent.BrokenBarrierException; import java.ut...

    技术蓝海
  • ArrayList实现原理分析(Java源码剖析)ArrayList使用的存储的数据结构ArrayList的初始化ArrayList是如何动态增长ArrayList如何实现元素的移除ArrayList

    ArrayList是我们经常使用的一个数据结构,我们通常把其用作一个可变长度的动态数组使用,大部分时候,可以替代数组的作用,我们不用事先设定ArrayList的...

    desperate633
  • Logistic Regression Models分析交互式问答译

    本文是一篇关于交互式问答系统中如何通过文本特征工程构建和Logistic Regression判定话题/主题/意图延续还是转换的论文,提供了一条比较好的思路,对...

    企鹅号小编
  • Logistic Regression Models分析交互式问答译

    本文是一篇关于交互式问答系统中如何通过文本特征工程构建和Logistic Regression判定话题/主题/意图延续还是转换的论文,提供了一条比较好的思路,对...

    企鹅号小编
  • 微信授权登录mock(在没有真实微信账号的情况下测试大量微信账户授权登录的情况)

    对于构建在微信公众号的系统,帐号体系往往使用微信授权登录(如各类微信商城应用系统)。

    lulianqi
  • 使用mui搜索框触发手机软键盘搜索按钮事件

    素描
  • 基于Qt的网络音乐播放器(四)酷狗API接口获取歌曲的搜索列表和歌曲的播放

    如果有一天,这个代码不能用了,要注意查询的值对不对,酷狗可能是为了防止被爬,data,info,等等这些值有可能被更换成别的,要观察json。

    花狗Fdog
  • 8.02-json_use

    hankleo

扫码关注云+社区

领取腾讯云代金券