java中ConcurrentModificationException异常警告怎么解决

发布时间:2022-06-02 16:20:50 作者:iii
来源:亿速云 阅读:218

这篇文章主要介绍“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异常警告怎么解决”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!

推荐阅读:
  1. python异常错误警告的区别是什么
  2. Java异常之OutOfMemoryError怎么解决

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

java

上一篇:python解析json的代码怎么写

下一篇:java支付功能怎么实现

相关阅读

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

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