Search code examples
javamultithreadingthreadpool

Java threads synchronization for printing a matrix (2d array)


Hello I am trying to print a matrix and split this work among different threads.

For example in the code below I tried to do the logic and it is working fine for 1 thread.

For multiple threads I think I somehow need to synchronize the start and end so that each thread gets different values for these.

I want that for different threads to print different line(s) (depends on the number of threads) of that matrix (doesn't matter the order), but each thread needs to work with unique line(s).

Any ideas how can this be done?

import javax.swing.plaf.TableHeaderUI;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class Mythread {
    int[][] matrix;
    public Mythread(int nr){
        matrix = new int[nr][nr];
        for(int i = 0; i <nr; i++){
            for(int j = 0; j < nr; j++)
                matrix[i][j] = i;
        }
    }

    public void printMatrix(int start, int end){
        System.out.println("Start = " +start + ";thread"+Thread.currentThread().getId());
        System.out.println("End = " +end+ ";thread"+Thread.currentThread().getId());
        for(int i = start; i <end; i++){
            for(int j = 0; j < 4; j++) {
                System.out.print(matrix[i][j] + "<->");
            }
            System.out.println();
        }
    }

    public void testRun() throws InterruptedException {
        ExecutorService ex = Executors.newFixedThreadPool(1);
        for(int i=0 ; i < 4; i++) {
                final int start = i;
                final int end = i + 1;
                ex.execute(new Runnable() {
                    @Override
                    public void run() {
                        printMatrix(start, end);
                    }
                });
        }
        ex.shutdown();
        ex.awaitTermination(1, TimeUnit.MINUTES);
        System.out.println("DONE");

        /*
        works for nThreads = 1 -> for Thread Pool
        Start = 0;thread14
        End = 1;thread14
        0<->0<->0<->0<->
        Start = 1;thread14
        End = 2;thread14
        1<->1<->1<->1<->
        Start = 2;thread14
        End = 3;thread14
        2<->2<->2<->2<->
        Start = 3;thread14
        End = 4;thread14
        3<->3<->3<->3<->
        DONE
         */


    }



    public static void main(String[] args) throws InterruptedException {
        Mythread a = new Mythread(4);
        a.testRun();
    }
}

Solution

  • Here is a simple way you could accomplish your goal of using multiple threads to print the rows of a 2D integer array in no particular order:

    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.atomic.AtomicInteger;
    
    public class ConcurrentMatrixPrint {
        private int[][] matrix;
        public ConcurrentMatrixPrint(int nr){
            matrix = new int[nr][nr];
            for(int i = 0; i <nr; i++){
                for(int j = 0; j < nr; j++)
                    matrix[i][j] = i;
            }
        }
    
        public void printRow(int row){
            //Creates a builder and initializes with the thread id and a tab
            StringBuilder sb = new StringBuilder();
            sb.append(Thread.currentThread().getId());
            sb.append("\t");
    
            //Loop through columns in the current row
            for(int i = 0; i < matrix[row].length; i++){
                //Add the data in the current row and column to the builder
                sb.append(matrix[row][i]);
                //This just makes the output a little nicer, only adds comma if there
                //  is another item to print so there is no trailing comma at the end.
                if(i+1 < matrix[row].length){
                    sb.append(",");
                }
            }
            //Print the resulting comma separated string
            System.out.println(sb);
        }
    
        public void testRun() throws InterruptedException {
            //Use an atomic integer to prevent memory consistency issues
            AtomicInteger rowIndex = new AtomicInteger(0);
            ExecutorService ex = Executors.newFixedThreadPool(4);
            for(int i=0 ; i < matrix.length; i++) {
                    ex.execute(new Runnable() {
                        @Override
                        public void run() {
                            //Each thread will print a row based on the value
                            // of the atomic integer and will also increment
                            // that integer.
                            printRow(rowIndex.getAndIncrement());
                        }
                    });
            }
            ex.shutdown();
            ex.awaitTermination(1, TimeUnit.MINUTES);
            System.out.println("DONE");
        }
    
        public static void main(String[] args) throws InterruptedException {
            ConcurrentMatrixPrint a = new ConcurrentMatrixPrint(8);
            a.testRun();
        }
    }
    

    I have added comments within the code, but basically the threads all share an integer index which is atomic and incremented with each new task given to the executor.

    Note that the output shows the thread ID which was responsible for generating the line of text as the first value printed. So in the sample output below you can see thread 12 printed the first line, then thread 14 printed the next line, etc.

    Here is some sample output:

    12  1,1,1,1,1,1,1,1
    14  3,3,3,3,3,3,3,3
    11  0,0,0,0,0,0,0,0
    13  2,2,2,2,2,2,2,2
    11  6,6,6,6,6,6,6,6
    14  5,5,5,5,5,5,5,5
    12  4,4,4,4,4,4,4,4
    13  7,7,7,7,7,7,7,7
    DONE
    

    Hope this helps!