Search code examples
javamultithreadingsynchronize

How to remove manually created pauses in Main-thread?


Problem description:

We have a given matrix randomly filled with digits and have to create separate threads for each row of the matrix that count how many times the digits encounter in that row.

Without these sleeps in the main thread, it's not working correctly..

Here's my solution.

Also it's following here:

public class TestingMatrixThreads {

public static void main(String[] arr) throws InterruptedException {

    int[][] a = new int[67][6];
    // class.Count works with class.Matrix, that's why I've made it this way
    Matrix m = new Matrix(a);
    m.start();

    Thread.sleep(1000); // Here comes the BIG question -> how to avoid these
                        // manually created pauses

    Count c;
    Thread t;
    // Creating new threads for each row of the matrix
    for (int i = 0; i < Matrix.matr.length; i++) {
        c = new Count(i);
        t = new Thread(c);
        t.start();

    }

    //Again - the same question
    System.out.println("Main - Sleep!");
    Thread.sleep(50);
    System.out.println("\t\t\t\t\tMain - Alive!");

    int sum = 0;
    for (int i = 0; i < Count.encounters.length; i++) {
        System.out.println(i + "->" + Count.encounters[i]);
        sum += Count.encounters[i];
    }
    System.out.println("Total numbers of digits: " + sum);

}

}

class Count implements Runnable {

int row;
public static int[] encounters = new int[10]; // here I store the number of each digit's(array's index) encounters

public Count(int row) {
    this.row = row;
}

public synchronized static void increment(int number) {
    encounters[number]++;
}

@Override
public void run() {
    System.out.println(Thread.currentThread().getName() + ", searching in row " + row + " STARTED");
    
    for (int col = 0; col < Matrix.matr[0].length; col++) {
        increment(Matrix.matr[row][col]);
    }
    
    try {
        Thread.sleep(1); // If it's missing threads are starting and stopping consequently
    } catch (InterruptedException e) {
    }
    System.out.println(Thread.currentThread().getName() + " stopped!");
}

}

class Matrix extends Thread {

static int[][] matr;

public Matrix(int[][] matr) {
    Matrix.matr = matr;
}

@Override
public void run() {
    //print();
    fill();
    System.out.println("matrix filled");
    print();
}

public static void fill() {
    for (int i = 0; i < matr.length; i++) {
        for (int j = 0; j < matr[0].length; j++) {
            matr[i][j] = (int) (Math.random() * 10);
        }
    }
}

public static void print() {
    for (int i = 0; i < matr.length; i++) {
        for (int j = 0; j < matr[0].length; j++) {
            System.out.print(matr[i][j] + " ");
        }
        System.out.println();
    }
}

}

P.S. I'm sorry if this question is too stupid for you to answer, but I'm a newbie in Java programming, as well as it's my very first post in stackoverflow, so please excuse me for the bad formatting, too :) Thank you in advance!


Solution

  • To answer your main question:

    Thread.join();
    

    For example:

    public static void main(String[] args) throws Exception {
        final Thread t = new Thread(new Runnable() {
    
            @Override
            public void run() {
                System.out.println("Do stuff");
            }
        });
        t.start();
        t.join();
    }
    

    The start call, as you know, kicks off the other Thread and runs the Runnable. The join call then waits for that started thread to finish.

    A more advanced way to deal with multiple threads is with an ExecutorService. This detaches the threads themselves from the tasks they do. You can have a pool of n threads and m > n tasks.

    Example:

    public static void main(String[] args) throws Exception {
        final class PrintMe implements Callable<Void> {
    
            final String toPrint;
    
            public PrintMe(final String toPrint) {
                this.toPrint = toPrint;
            }
    
            @Override
            public Void call() throws Exception {
                System.out.println(toPrint);
                return null;
            }
    
        }
        final List<Callable<Void>> callables = new LinkedList<>();
        for (int i = 0; i < 10; ++i) {
            callables.add(new PrintMe("I am " + i));
        }
        final ExecutorService es = Executors.newFixedThreadPool(4);
        es.invokeAll(callables);
        es.shutdown();
        es.awaitTermination(1, TimeUnit.DAYS);
    }
    

    Here we have 4 threads and 10 tasks.

    If you go down this route you probably need to look into the Future API to so that you can check whether the tasks completed successfully. You can also return a value from the task; in your case a Callable<Integer> would seem to be appropriate so that you can return the result of your calculation from the call method and gather up the results from the Future.