温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

java中ConcurrentModificationException异常警告怎么解决

发布时间:2022-06-02 16:20:50 阅读:234 作者:iii 栏目:大数据
Java开发者专用服务器限时活动,0元免费领,库存有限,领完即止! 点击查看>>

这篇文章主要介绍“java中ConcurrentModificationException异常警告怎么解决”,在日常操作中,相信很多人在java中ConcurrentModificationException异常警告怎么解决问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”java中ConcurrentModificationException异常警告怎么解决”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

异常分析

相信写过一些Java代码的人都遇到过这个异常,一般都是由以下代码引起的:

import java.util.List;import java.util.ArrayList;public class Test{    public static void main(String[] args){      List<String> list = new ArrayList<>();      list.add("123");      list.add("456");      list.add("789");      for(String obj : list){          list.remove(obj);      }    }}

上述代码最终会引发java.util.ConcurrentModificationException,那么为什么呢?首先我们将上述代码反编译,得到如下结果(如果对foreach语法糖比较了解可以忽略):

public class Test {  public Test();    Code:       0: aload_0       1: invokespecial #1                  // Method java/lang/Object."<init>":()V       4: return    LineNumberTable:      line 4: 0  public static void main(java.lang.String[]);    Code:       0: new           #2                  // class java/util/ArrayList       3: dup       4: invokespecial #3                  // Method java/util/ArrayList."<init>":()V       7: astore_1       8: aload_1       9: ldc           #4                  // String 123      11: invokeinterface #5,  2            // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z      16: pop      17: aload_1      18: ldc           #6                  // String 456      20: invokeinterface #5,  2            // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z      25: pop      26: aload_1      27: ldc           #7                  // String 789      29: invokeinterface #5,  2            // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z      34: pop      35: aload_1      36: invokeinterface #8,  1            // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;      41: astore_2      42: aload_2      43: invokeinterface #9,  1            // InterfaceMethod java/util/Iterator.hasNext:()Z      48: ifeq          72      51: aload_2      52: invokeinterface #10,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;      57: checkcast     #11                 // class java/lang/String      60: astore_3      61: aload_1      62: aload_3      63: invokeinterface #12,  2           // InterfaceMethod java/util/List.remove:(Ljava/lang/Object;)Z      68: pop      69: goto          42      72: return    LineNumberTable:      line 6: 0      line 7: 8      line 8: 17      line 9: 26      line 10: 35      line 11: 61      line 12: 69      line 13: 72}

将上述代码翻译出来等价于下列代码:

import java.util.List;import java.util.ArrayList;import java.util.Iterator;public class Test{    public static void main(String[] args){      List<String> list = new ArrayList<>();      list.add("123");      list.add("456");      list.add("789");      Iterator<String> iterator = list.iterator();      while (iterator.hasNext()){          String obj = iterator.next();          list.remove(obj);      }    }}

然后我们查看iterator.hasNext()源码,可以发现第一行调用了checkForComodification方法,我们查看这个方法:

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

modCount != expectedModCount这个条件成立的时候会抛出ConcurrentModificationException异常,那么这个条件是怎么成立的呢?

1、首先我们查看modCount的来源,可以发现modCount的值等于当前List的size,当调用List.remove方法的时候modCount也会相应的减1;

2、然后我们查看expectedModCount的来源,可以看到是在构造Iterator(这里使用的是ArrayList的内部实现)的时候,有一个变量赋值,将modCount 的值赋给了expectedModCount

3、最后当我们执行循环调用List.remove方法的时候,modCount改变了但是expectedModCount并没有改变,当第一次循环结束删除一个数据准 备第二次循环调用iterator.hasNext()方法的时候,checkForComodification()方法就会抛出异常,因为此时ListmodCount已经变为 了2,而expectedModCount仍然是3,所以会抛出ConcurrentModificationException异常;

解决方法

那么如何解决该问题呢?我们查看java.util.ArrayList.Itr(ArrayList中的Iterator实现)的源码可以发现,在该迭代器中有一个remove方法可以 删除当前迭代元素,而且会同时修改modCountexpectedModCount,这样在进行checkForComodification检查的时候就不会抛出异常了,该remove 方法源码如下:

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();    }}

其中ArrayList.this.remove(lastRet);这一行会改变modCount的值,而后边会同步的修改expectedModCount的值等于modCount的值;

现在修改我们开头的程序如下就可以正常运行了:

import java.util.List;import java.util.ArrayList;import java.util.Iterator;public class Test{    public static void main(String[] args){      List<String> list = new ArrayList<>();      list.add("123");      list.add("456");      list.add("789");      Iterator<String> iterator = list.iterator();      while (iterator.hasNext()) {          System.out.println("移除:" + iterator.next());          iterator.remove();      }    }}

到此,关于“java中ConcurrentModificationException异常警告怎么解决”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!

亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

原文链接:https://my.oschina.net/u/4607179/blog/4477204

AI

开发者交流群×