0

I would like to populate the cells of a nRows * nCols matrix concurrently with random integers. The runnable here is just a setter that sets a cell of the matrix to a random integer.

public class ConcurrentMatrix {

    private int nRows;
    private int nCols;
    private int[][] matrix = new int[nRows][nCols];

    private MyConcurrentMatrixFiller myConcurrentMatrixFiller;

    public ConcurrentMatrix(int nRows, int nCols, MyConcurrentMatrixFiller filler) {
        this.nRows = nRows;
        this.nCols = nCols;
        this.matrix = new int[nRows][nCols];
        Random r = new Random();
        for (int row=0; row<nRows; row++) {
            for (int col=0; col<nCols; col++) {
                Runnable runnable = new Runnable() {
                    public void run() {
                        matrix[row][col] = r.nextInt(100);
                    }
                };
                filler.execute(runnable); // non-blocking, just depositing runnable in queue.
            }
        }
    }
}

And the filler starts the thread pool:

public class MyConcurrentMatrixFiller implements Executor {
    BlockingQueue<Runnable> channel = new LinkedBlockingQueue<>();

    @Override
    public void execute(Runnable command) {
        channel.offer(command);
    }

    public MyConcurrentMatrixFiller(int nthreads) {
        for (int i=0; i<nthreads; i++) {
            activate();
        }
    }

    private void activate() {
        new Thread(() -> {
            try {
                while (true) { channel.take().run(); }
            } catch (InterruptedException e) { }
        }).start();
    }   

    public static void main(String[] args) {
        MyConcurrentMatrixFiller filler = new MyConcurrentMatrixFiller(10);
        ConcurrentMatrix cm = new ConcurrentMatrix(10, 10, filler);
    }
}

However, my IDE complains that the row and col indeces should be final. But I need every runnable to care about it's own cell, so how can I provide these values to the runnable?

TMOTTM
  • 3,286
  • 6
  • 32
  • 63
  • 1
    It's because you are creating an anonymous class which captures the variables. You could simply write a class implementing Runnable. Or maybe you can declare two final vars and assign them i,j before declaring your Runnable, not sure. Btw. using a thread for a single random number seems...overkill. Maybe you want to do it per row/col? – Benjamin Maurer Jun 26 '20 at 13:30
  • 2
    you can declare final int for both row, and col and pass that to the thread final int myRow = row; find int myCol = col; matrix[myRow][myCol] – Don Ha Jun 26 '20 at 13:34
  • I was sure I had tried that.. – TMOTTM Jun 26 '20 at 14:04
  • Nice with a thread per row... but it dies at 100x100... – TMOTTM Jun 26 '20 at 14:05

1 Answers1

1

Best solution would be to create new class that extends the runnable and which accepts all parameters that it will need use. In this case it's matrix, random seed r and row and col. In your case it would look like this:

You new class:

public class MyExecutor extends Runnable {
    private final int[][] matrix;
    private final Random r;
    private final int row;
    private final int col;
    public MyExecutor( int[][] matrix, Random r, int row, int col ) {
        this.matrix = matrix;
        this.r = r;
        this.row = row;
        this.col = col;
    }

    @Override
    public void run() {
        matrix[row][col] = r.nextInt(100);
    }
}

And your ConcurrentMatrix:

public ConcurrentMatrix(int nRows, int nCols, MyConcurrentMatrixFiller filler) {
    this.nRows = nRows;
    this.nCols = nCols;
    this.matrix = new int[nRows][nCols];
    Random r = new Random();
    for (int row=0; row<nRows; row++) {
        for (int col=0; col<nCols; col++) {
            Runnable runnable = new MyExecutor( row, col );
            filler.execute(runnable); // non-blocking, just depositing runnable in queue.
        }
    }
}
n1t4chi
  • 502
  • 2
  • 12