-2

As soon as I submit a Runnable to the ThreadExecutor, it quits and I can't figure out why. I've traced the code, but to no avail. Does anyone have any idea why this would be?

By quits, i mean the task is submitted and it never runs the Multiplier class (run method) - the first submission to the ThreadPool just closes the whole program with exit code 0.

public class Main {
    public static void main(String[] args) {

        /**
        * 0: threads
        * 1: matrix A
        * 2: matrix B
        * 3: matrix C -- output file
        */
        Object[] parsedArgs = CommandLineArgParser.getArguments(args); // strip arguments -- contains help and exit upon incorrect entries

        try {
            // Create thread pool
            int threads = Integer.parseInt((String) parsedArgs[0]);
            ExecutorService threadPool;
            if (threads > 0) {
                threadPool = Executors.newFixedThreadPool(threads*2); // create twice as many threads as OS cores
            }else
            throw new InputMismatchException("Threads must be an Integer");

            // Create matrices:
            Matrix m1 = getMatrix((String) parsedArgs[1]);
            Matrix m2 = getMatrix((String) parsedArgs[2]);
            Matrix m3 = null;
            try {
                m3 = m1.multiply(m2, threadPool);
                } catch (ExecutionException exE) {
                System.exit(1);
                } catch (InterruptedException iE) {
                System.exit(1);
            }
            threadPool.shutdown();

            try {
                threadPool.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
                } catch (InterruptedException e) {
                System.out.println("The operation is taking too long. Exiting.");
                System.exit(1);
            }

            // Write to file!
            m3.writeToFile((String)parsedArgs[3]);

            }catch (ArrayIndexOutOfBoundsException arrayOutBounds) {
            // means that correct arguments were not passed in. print them.

        }

    }

    public static Matrix getMatrix(String filePath) {
        try {
            return MatrixCreator.createMatrix(filePath);
            } catch (IOException ioE) {
            // Matrix could not be found in filesystem
            System.out.println("The matrix path (" + filePath +") supplied could not be found in the filesystem. If you have not already, try an absolute path.");
            System.exit(0); //exit so that user may re-enter
        }
        return null; // should never happen
    }
}

public class Matrix {

    int rows, cols; // number of rows and columns in matrix, respectively.
    Double [][] matrix;

    public Matrix(int rows, int cols) {
        this.rows = rows;
        this.cols = cols;
        matrix = new Double[rows][cols]; // create matrix of proper size
    }

    /**
    * Inserts value into matrix
    * @param row row in which to insert element
    * @param col column in which to insert element
    * @param val
    */
    public void insertValue(int row, int col, double val) {
        matrix[row][col] = val; // no error checking applied for column or row -- would reduce speed when inserting thousands of values
    }

    /**
    * A is THIS matrix. <code>multiply()</code> computes AB = C.
    * @param B matrix by which to multiply
    * @param threadPool thread pool to use
    * @return matrix C
    */
    public Matrix multiply(Matrix B, ExecutorService threadPool) throws ExecutionException, InterruptedException {
        System.out.println("In multiply..");
        Matrix C = new Matrix(this.rows, B.cols); // create matrix C of appropriate size
        ArrayList<Future<?>> futures = new ArrayList<Future<?>>();
        for (int i = 0; i < C.rows; i++) {
            System.out.println(C.rows);
            for (int j = 0; j < C.cols; j++) {
                System.out.println(C.cols);
                System.out.println("Here");
                futures.add(threadPool.submit(new Multiplier(this.getColumnsOfRow(i), B.getRowsOfColumn(j), C, i, j)));
            }
        }
        for (Future<?> f : futures) {
            f.get();
        }
        return C;
    }

    private Double[] getRowsOfColumn(int column) {
        Double[]  rowsOfColumn = new Double[rows];
        for (int i = 0; i < rows; i++) {
            rowsOfColumn[i] = this.matrix[i][column];
        }
        return rowsOfColumn;
    }

    private Double[] getColumnsOfRow(int row) {
        Double[] columnsOfRow = new Double[cols];
        for (int i = 0; i < cols; i++) {
            columnsOfRow[i] = this.matrix[row][cols];
        }
        return columnsOfRow;
    }

    // make string...
    public String toString() {
        String s = "";
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                s += matrix[i][j] + ", ";
            }
            s += "\n";
        }
        return s;
    }

    // write file to path provided
    public void writeToFile(String filePath) {
        System.out.println("Saving to: " + filePath);
        try {
            BufferedWriter writer = new BufferedWriter(new FileWriter(filePath, false));
            for (int i = 0; i < rows; i++) {
                for (int j = 0; j < cols; j++) {
                    if (j == cols - 1) {
                        writer.write("" + matrix[i][j] + "\n");
                        } else {
                        writer.write("" + matrix[i][j] + ",");
                    }
                }
            }
            writer.close();
            } catch (IOException ioE) {
            System.out.println("Could not save file to specified location. Printing stacktrace:");
            ioE.printStackTrace();
            System.exit(1);
        }
        System.out.println("Matrix successfully written to file: " + filePath);
    }

    class Multiplier implements Runnable {

        Double[] ARow, BCol;
        Matrix C;
        int insertRow, insertCol;
        /**
        * This will method will multiply the row of matrix A and the
        * column of matrix B on a thread.  The result will be put into
        * matrix C at the specified locations.
        * @param ARow the Row to be multiplied by the column of matrix B
        * @param BCol the Column to be multiplied by the row of matrix A
        * @param C the matrix which will hold the resultant of the two operations.
        * @param insertRow  the row of matrix C in which to insert the multiplication
        * @param insertCol  the column of matrix C in which to insert the multiplication
        */
        public Multiplier(Double[] ARow, Double[] BCol, Matrix C, int insertRow, int insertCol) {
            System.out.println("We are here!");
            this.ARow = ARow;
            this.BCol = BCol;
            this.C = C;
            this.insertRow = insertRow;
            this.insertCol = insertCol;
        }

        @Override
        public void run() {
            double sum = 0;
            for (int i = 0; i < ARow.length; i++) {
                sum += ARow[i]*BCol[i];
            }
            C.insertValue(insertRow,insertCol,sum);
        }
    }

Command line args used -t 8 -m1 /Users/me/Desktop/Matrices/matrixA.mat -m2 /Users/me/Desktop/Matrices/matrixB.mat -o /Users/me/Desktop/Matrices/output.mat

Chris Hayes
  • 11,471
  • 4
  • 32
  • 47
HelloWorld
  • 605
  • 1
  • 7
  • 22

2 Answers2

0

Your program can't just submit a job and terminate. So, once you have submitted all the jobs, you'll have to do the following:

Future<Void> result = threadPool.submit(new Multiplier(this.getColumnsOfRow(i), 
                                                B.getRowsOfColumn(j), C, i, j));
result.get()

This will ensure your code waits for the thread to complete before terminating the main thread.

Also, you could take a look at CompletionService. See this for example.

[Based on Edit]

public Matrix multiply(Matrix B, ExecutorService threadPool) {
    System.out.println("In multiply..");
    Matrix C = new Matrix(this.rows, B.cols); // create matrix C of appropriate size
    ArrayList<Future<?>> futures = new ArrayList<Future<?>>();
    for (int i = 0; i < C.rows; i++) {
        System.out.println(C.rows);
        for (int j = 0; j < C.cols; j++) {
            System.out.println(C.cols);
            System.out.println("Here");
            futures.add(threadPool.submit(new Multiplier(this.getColumnsOfRow(i), B.getRowsOfColumn(j), C, i, j)));
        }
    }
    for(Future<?> future: futures) {
        future.get()
    }
    return C;
}

This will ensure that you're waiting for the threads to complete, before you actually pull the result of multiplication. Your code might require a bit of refactoring for this.

Aritra
  • 1,234
  • 12
  • 20
  • Why is any of this necessary in their current setup? – Sotirios Delimanolis Oct 01 '14 at 03:16
  • I am assuming this is dummy code for learning about the Java concurrent packages, and not a code review. – Aritra Oct 01 '14 at 03:18
  • It's pseudo code for what i'm writing, but this doesn't work. __As soon as__ the task is submitted to the ExecutorService, the program quits. I have posted all applicable code. – HelloWorld Oct 01 '14 at 03:19
  • The thing is, if you don't do a get(), you'll not know if any of the threads terminated with an exception or they terminated normally. Hence, it's better to use a callable instead, and gather the success of a thread from the return of the callable. It is possible that your Matrix class is not allowed to be modified concurrently (which is what you're doing with the Matrix C), and all threads are terminating with errors immediately. Since your Runnable is not printing any logs, there's no way to know till you gather the status of threads individually by walking through the Futures. – Aritra Oct 01 '14 at 03:25
  • i'm not getting any futures to walk through – HelloWorld Oct 01 '14 at 03:55
0

Your code here

private Double[] getColumnsOfRow(int row) {
    Double[] columnsOfRow = new Double[cols];
    for (int i = 0; i < cols; i++) {
        columnsOfRow[i] = this.matrix[row][cols];
    }
    return columnsOfRow;
}

will use cols with a value of 20. But your matrix was created as

matrix = new Double[rows][cols]; // 20 x 20

so the last index is 19. This throws an ArrayIndexOutOfBoundsException which you swallow and your app ends with status code 0 as the method returns normally.

Change it to

columnsOfRow[i] = this.matrix[row][i];
Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724