多线程时线程 "main" java.util.ConcurrentModificationException 出现异常

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

我正在开发一个多线程程序,目的是通过三个线程同时在列表中添加 150000 名学生,这意味着每个线程将添加 50000。这是以下程序:

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

我想做的是从 Main class 调用方法 threadsL,将学生列表添加到数据库中,然后计算执行时间的平均值执行 15 次。

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

Main.java class 中,我得到以下异常:

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)

第 27 行是:

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

你能帮我解决这个问题吗?

提前感谢您的帮助!

你的程序几乎没有问题。

  1. 在 ThreadStudents 的所有线程完成之前,您的程序正在返回主线程。所以你试图在所有线程都写入之前读取,这就是你得到 concurrentModification exception

    的原因
  2. students 是一个 ArrayList 对象,这意味着它不是线程安全的。

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

我的输出完全符合预期,即 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