2

I had an ArrayList that was being operated on by multiple threads, which wasn't working as the ArrayList isn't synchronized. I switched the list to a Vector as instructed by my professor. Vector is synchronized, but I'm having exceptions thrown related to synchronization.

Why is this happening, and how can I avoid concurrency exceptions in my code? I don't want to just play around until something works, I want to do the best thing. Thanks!

Exception:

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)

Code:

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

}
brienna
  • 1,415
  • 1
  • 18
  • 45

2 Answers2

4

Your code seems wrong.

I don't see why you need a shared vector, if each thread is to calculate the sum of records from an individual file. On the other hand, if you want to calculate the sum of records from all files, you should do it after every thread has completed.

Depending on which you want, you can either 1) create a vector for each thread and calculate the sum for each file or, 2) in the main thread, wait for all threads to complete then calculate the sum for all files.

xiaofeng.li
  • 8,237
  • 2
  • 23
  • 30
4

From the 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.

The following code creates an iterator under the covers:

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

So when one threads modifies the vector (by adding elements) while another vector is iterating it - you'll see a ConcurrentModificationException

There are different options to solve it, one way could be to read from a file into another vector and when the reading is done assign this other vector to numbers (since assignment is an atomic operation). Keep in mind that in order for the change to be visible to other threads you'll need to declare numbers as volatile.

Nir Alfasi
  • 53,191
  • 11
  • 86
  • 129
  • Thank you. Each thread now contains its own ArrayList that is added to the main Vector after the thread completes. The iterator accesses this ArrayList, so there is no concurrency problem. – brienna Nov 10 '17 at 02:21