Search code examples
javamultithreadingparallel-processingsynchronizationjava-threads

Exception in thread "main" java.util.ConcurrentModificationException while multithreading


I am developing a multithreaded program with the intention of adding 150000 students in a list at the same time by three threads, which means each of them will add 50000. Here is the following program:

public class ThreadsStudents implements Runnable {
    
    public static List<Student> students = new ArrayList<>();
    
    @Override
    public void run() {
        for(int i = 0; i < 50000; i++) {
            students.add(Generator.generetorStudent());
        }
    }
    
    public static void threadsL(int nbThreads) {
        ArrayList<Thread> th = new ArrayList<>();
        for(int i = 0; i < nbThreads; i++) {
            th.add(new Thread(new ThreadsStudents()));
        }
        for(Thread threads: th) {
            threads.start();
        }
    }
}

What I am trying to do is to call the method threadsL from Main class, add the list of students in a database and then do an average of the execution time for 15 executions.

public class Main {
    public static void main(String[] argv) {
        
        long startDate,endDate;
        double measure;
        double average = 0;

        ManipulationBDD basedd = new ManipulationBDD();

        for (int i = 0; i < 15; i++) {
            startDate = System.nanoTime();
            ThreadsStudents.threadsL(3);
            
            for(Student e : ThreadsStudents.students) {
                basedd.insertTable(e);
            }
            endDate = System.nanoTime();
            measure = (double) (endDate - startDate) / 1000000000;
            average = average + measure;
            basedd.empty();
        }
        average = average / 15;
        System.out.println("The average is : " + average);
    }
}

In the Main.java class, I get the following Exception:

Exception in thread "main" java.util.ConcurrentModificationException
    at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1043)
    at java.base/java.util.ArrayList$Itr.next(ArrayList.java:997)
    at Main.main(Main.java:27)

Line 27 is:

for(Student e : ThreadsStudents.students) {
    basedd.insertTable(e);
}

Can you help me with this?

Thank you in advance for your help !


Solution

  • There are few problems with your program.

    1. Your program is coming back to main thread before all the threads of ThreadStudents are finished. So you are trying to read before all the threads have written, which is why you are getting concurrentModification exception

    2. students is a ArrayList object which means it is not thread safe.

      public class Main {
          public static void main(String[] argv) {
      
              for (int i = 0; i < 1; i++) {
                  ThreadStudents.threadsL(3);
                  System.out.println(ThreadStudents.students.size());
              }
          }
      }
      
      
      
      public class ThreadStudents implements Runnable {
      
          public static List<Integer> students = new CopyOnWriteArrayList<>(); 
          // Thread safe version of array list
      
          @Override
          public void run() {
              System.out.println("Starting: " + Thread.currentThread().getName());
              for(int i = 0; i < 50000; i++) {
                  students.add(1);
              }
              System.out.println("Ending " + Thread.currentThread().getName());
          }
      
          public static void threadsL(int nbThreads) {
              ExecutorService executor = Executors.newFixedThreadPool(nbThreads); 
               // creates fixed number of threads
              for(int i = 0; i < nbThreads; i++) {
                  executor.execute(new ThreadStudents()); 
                 // executor services will call run() from each thread
              }
              executor.shutdown(); // tell the service that no new threads can be submitted
      
              while(true) {
                  try {
                      if (executor.awaitTermination(5, TimeUnit.MINUTES)) break;
                      // it will wait till all the threads have finished or Max 5 mins 
                      // before going back to main thread
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }
      
          }
      }
      

    My output is exactly as expected which is 150,000.

    Starting: pool-1-thread-3
    Starting: pool-1-thread-1
    Starting: pool-1-thread-2
    Ending pool-1-thread-3
    Ending pool-1-thread-1
    Ending pool-1-thread-2
    150000