java - 使用多线程向 ArrayList 添加元素时,有时会给出 ConcurrentModificationException,有时则不会?

标签 java arraylist collections concurrent-collections

我尝试使用多线程迭代ArrayList对象,但有时会给出ConcurrentModificationException,有时则不会?我无法理解这里发生了什么。

我在下面分享我的代码:

import java.util.ArrayList;
import java.util.Iterator;

public class ConcurrentDemo extends Thread{
    static ArrayList l=new ArrayList();
    public void run()
    {
        /*
         * try { Thread.sleep(2000); } catch(InterruptedException e) { }
         */
        System.out.println("child thread updating list");
        l.add("D");
        System.out.println(l);

    }

    public static void main(String args[]) throws InterruptedException
    {
        l.add("A");
        l.add("B");
        l.add("c");
     ConcurrentDemo c=new ConcurrentDemo();
      c.start();
      System.out.println(l);
      Iterator itr =l.iterator();
      while(itr.hasNext())
      {
          String s1=(String)itr.next();
          System.out.println("main thread list:" + s1);
          Thread.sleep(3000);
      }
      System.out.println(l);
    }
}

最佳答案

请在您的代码中内联查看我的答案:

import java.util.ArrayList;
import java.util.Iterator;

public class ConcurrentDemo extends Thread{
    static ArrayList l=new ArrayList();
    public void run()
    {

        System.out.println("child thread updating list");
        l.add("D");
        System.out.println(l);

    }

    public static void main(String args[]) throws InterruptedException
    {  

        //----> Main thread starts here
        l.add("A");
        l.add("B");
        l.add("c");  

     //----> l now contains A,B,C  

     ConcurrentDemo c=new ConcurrentDemo();  

      //----> You have started a second thread here
      c.start();    

      //-----> Its not determined, which line will be executed first from now on, as 2 threads are running parallelly, the ConcurrentModificationException most likely occur in cases, when the "l.add("D");" called within the "run();" method AFTER the Iterator has been created.   

      System.out.println(l);
      Iterator itr =l.iterator();
      while(itr.hasNext())
      {
          String s1=(String)itr.next();
          System.out.println("main thread list:" + s1);
          Thread.sleep(3000);
      }
      System.out.println(l);
    }
}    

请注意,关于迭代器,如果在迭代过程中以除调用 Iterator 接口(interface)上的适当方法之外的任何方式修改底层集合,则迭代器的行为是未指定的。 Reference

Instead of randomly failing when you do this, the collection is nice enough to keep track of how many times it's been modified, and throw ConcurrentModificationException when it detects concurrent modification. Reference

如果您计划通过添加新元素来修改迭代器的基础集合,请考虑使用 ListIterator

您的代码示例:

  static ArrayList l=new ArrayList();
  ListIterator listItr =l.listIterator();
  listItr.add(e);

有关更多信息,请查看此 Java Concurrency and Multithreading tutorial

编辑:
由于可能很难注意到,我突出显示了上面代码中最重要的内联注释:

调用c.start();后,不确定先执行哪一行,因为2个线程并行运行,ConcurrentModificationException最有可能发生在以下情况:l.add("D");创建迭代器之后run(); 方法中调用。

关于java - 使用多线程向 ArrayList 添加元素时,有时会给出 ConcurrentModificationException,有时则不会?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59265410/

相关文章:

java - @Transactional 和执行时间

java - 如何从本地连接的 JNDI 查找 DomainRuntimeServiceMBean?

c# - 如何避免手动实现 INotifyPropertyChanged

java - 切换窗口在 selenium webelement java 中不起作用

java - java中重命名的文件路径如何保持不变?

java - 如何将列表的值传递给隐藏标签?

java - Java 中的 ArrayList<DisplayMode> 空指针异常

java - 使用比较器在 ArrayList 中搜索

java - 不可修改集合中的 ConcurrentModificationException

java - 为什么Map接口(interface)不限制key泛型扩展Comparable?