2

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

4

1 回答 1

2

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

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

请注意关于迭代器,如果在迭代进行时以任何方式修改底层集合,而不是通过调用迭代器接口上的适当方法,迭代器的行为是未指定的。参考

当您这样做时,集合不会随机失败,而是足以跟踪它被修改的次数,并在检测到并发修改时抛出 ConcurrentModificationException。参考

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

您的代码示例:

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

有关更多信息,请查看此Java 并发和多线程教程

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

在你调用c.start();它之后不确定,首先执行哪一行,因为2个线程并行运行,ConcurrentModificationException很可能发生在创建Iterator 之后的方法l.add("D");内调用的情况下。run();

于 2019-12-10T12:15:12.317 回答