使用多线程将元素添加到 ArrayList 中时,有时它会给出 ConcurrentModificationException 有时不会?

While adding element into ArrayList using Multithreading, sometimes it give ConcurrentModificationException and sometimes not?

我尝试使用多线程迭代 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);
    }
}    

请注意关于迭代器,如果在迭代过程中以任何方式修改基础集合而不是通过调用迭代器接口上的适当方法,则迭代器的行为是未指定的。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(); 方法中调用 迭代器创建之后。