javaarraylistcollectionsconcurrent-collections

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


I tried iterating ArrayList object using multi-threading, but sometimes it is giving ConcurrentModificationException and sometimes not? I am unable to understand what is happening here.

I am sharing my code below:

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


Solution

  • Please see my answer inline in your code:

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

    Please note regarding to interators, that the behavior of an iterator is unspecified if the underlying collection is modified while the iteration is in progress in any way other than by calling the appropriate method on the 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

    If you plan to modify the underlying collection of an iterator by adding new elements, consider using the ListIterator

    Example with your code:

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

    For further informations, check out this Java Concurrency and Multithreading tutorial.

    EDIT:
    As it might be hard to notice, I am highlighting the most important inline comment within the code above:

    After you have called c.start(); its not determined, which line will be executed first, 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.