2

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

metropolision
  • 405
  • 4
  • 10
Karan Dodwani
  • 31
  • 1
  • 5
  • You are iterating over the `List` on the main thread and make a structural change in another thread, so of course `ConcurrentModificationException` is possible. Are you asking why it doesn't always happen? – Eran Dec 10 '19 at 10:47
  • @kayaman I believe this is a wrong duplicate target, since that question is about `ConcurrentModificationException` with a single thread (removing while iterating). In this question there are 2 threads - one iterating and the other making structural changes. – Eran Dec 10 '19 at 10:50
  • @Eran well, the top 3 answers are about how to remove with CME, but other answers indicate that it's not about multithreading at all, how it's not guaranteed to be noticed, as well as how the check is actually performed (checkForComodification()). It's a bit hard to find a "pure" dupe unrelated to the usual use case (CME when removing). – Kayaman Dec 10 '19 at 10:52
  • @Kayaman precisely - the duplicate target is **not** about multithreading while this question **is**. – Eran Dec 10 '19 at 10:56
  • 1
    Well, I read this question more like "I don't really understand what CME, but it sounds multithreaded". But I'll reopen it. – Kayaman Dec 10 '19 at 10:59
  • @Eran : Yes i am asking why it doesn't always happen ? – Karan Dodwani Dec 12 '19 at 13:38
  • @KaranDodwani I guess it depends on whether the 2nd thread adds the last element to the list before or after the main thread starts iterating over it. – Eran Dec 12 '19 at 13:41

1 Answers1

2

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.

Oliver
  • 1,218
  • 1
  • 17
  • 21
  • I don't think this answers the question. – João Rebelo Dec 11 '19 at 13:43
  • 1
    The answer contains inline explanation within the OP's code, stating the most likely cause of the exception. Also showing the method of how to avoid it, plus additional information on the overall topic, all supported by linked references. If you think your view on the question is more accurate, please do not hesitate to improve the quality of this thread, by posting it as an answer. – Oliver Dec 11 '19 at 14:49
  • 1
    I'm sorry, I didn't read the inline code. I think you should post that as part of the answer instead of inlining it. That completes the answer you gave. – João Rebelo Dec 11 '19 at 15:23
  • @Karan Dodwani: Please consider accepting my post as an answer and/or upvote, if it helps. – Oliver Dec 11 '19 at 16:45
  • @Z3d4s : I understand your ans. but still my concern is why it doesn't always throw ConcurrentModificationError, Sometimes it give Exception and sometimes not ? Hope you understand my doubt.? – Karan Dodwani Dec 12 '19 at 13:44
  • Read this part: 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... **as you dealing with two threads parallelly** sometimes l.add("D"); will occur BEFORE the Iterator has been created sometimes AFTER the Iterator has been created, in cases when l.add("D"); occur AFTER the Iterator has been created you will see the ConcurrentModificationException. – Oliver Dec 12 '19 at 13:51
  • In your code, running 2 threads parallelly leads to **nondeterministic result**, that's why sometimes you see the exception happening sometimes not. – Oliver Dec 12 '19 at 13:56
  • 1
    @Z3d4s : Thank you so much... i got it – Karan Dodwani Dec 12 '19 at 17:43
  • @Karan I am glad that you have understood it! Could you please accept my answer via the green tick next to my answer? – Oliver Dec 12 '19 at 18:29