尽管已同步,但 Vector 仍抛出 ConcurrentModificationException

Vector throws ConcurrentModificationException despite being synchronized

我有一个由多个线程操作的 ArrayList,由于 ArrayList 未同步,它无法正常工作。我按照教授的指示将列表切换为 Vector。 Vector 是同步的,但我抛出了与同步相关的异常。

为什么会发生这种情况,如何避免代码中出现并发异常?我不想在某些事情奏效之前一直玩,我想做最好的事情。谢谢!

异常:

Exception in thread "Thread-3" java.util.ConcurrentModificationException
    at java.util.Vector$Itr.checkForComodification(Vector.java:1184)
    at java.util.Vector$Itr.next(Vector.java:1137)
    at BytePe4D$ReadInts.run(BytePe4D.java:64)

代码:

import java.io.*;
import java.util.Vector;

public class BytePe4D {
    private Vector<Integer> numbers;

    public static void main(String[] args) {
        new BytePe4D();
    }

    public BytePe4D() {
        // Create ArrayList and reset sum
        numbers = new Vector<Integer>();

        // Call addInts 8 times, with filenames integer1.dat through integer8.dat
        for (int i = 1; i <= 8; i++) {
            File file = new File("PE Data/integer" + i + ".dat");
            ReadInts thread = new ReadInts(file);
            thread.start();
        }
    }

    /** Represents a Thread instance */
    class ReadInts extends Thread {
        File file;

        public ReadInts(File _file) {
            file = _file;
        }

        @Override
        public void run() {
            int count = 0;  // track number of records read
            int sum = 0;

            try {
                // Open stream to binary data file integer1.dat
                FileInputStream in = new FileInputStream(file);
                // Buffer the stream
                BufferedInputStream bin = new BufferedInputStream(in);
                // Access the primitive data
                DataInputStream din = new DataInputStream(bin);

                try {
                    // Read file until end reached
                    while (true) {
                        numbers.add(din.readInt());
                        count++;
                    }
                } catch (EOFException eof) {
                    // System.out.println("End of file reached.");
                } finally {
                    // Close streams
                    din.close();
                }
            } catch (FileNotFoundException fnf) {
                System.out.println("File does not exist: " + file.getName());
                return;
            } catch (IOException ioe) {
                ioe.printStackTrace();
            }

            // Calculate sum of numbers read
            for (int num : numbers) {
                sum += num;
            }

            // Write info
            System.out.println(
                String.format("%s%s%-5s%s%-8d%-5s%s%-12d%-5s%s%d",
                "Filename = ", file.getName(), "",
                "Count = ", count, "",
                "Sum = ", sum, "",
                "In List = ", numbers.size()));
        }
    }

}

您的代码似乎有误。

如果每个线程要计算单个文件的记录总和,我不明白您为什么需要共享向量。另一方面,如果你想计算所有文件的记录总和,你应该在每个线程完成后计算。

根据需要,您可以 1) 为每个线程创建一个向量并计算每个文件的总和,或者 2) 在主线程中,等待所有线程完成,然后计算所有线程的总和文件。

来自docs

if the vector is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException.

以下代码在幕后创建了一个迭代器:

for (int num : numbers) {
    sum += num;
}

所以当一个线程修改向量(通过添加元素)而另一个向量迭代它时 - 你会看到 ConcurrentModificationException

有不同的解决方案,一种方法是从文件读取到另一个向量,读取完成后将另一个向量分配给 numbers(因为分配是原子操作)。请记住,为了让更改对其他线程可见,您需要将 numbers 声明为 volatile.