Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to run a task once every Threads finished running in Java?

I have a loop which create a new Thread on each iteration, like so:

for(int i = 0; i < REPEAT; i++) {
    new Thread(new MyTask(i)).start();
    Thread.sleep(1);
}

private void finalTask() {
    //Some code to be executed once every threads stopped running
}

Where MyTask is a class implementing Runnable. My goal is: I would like to run finalTask once every threads stopped. To achieve this, I have tried incrementing a variable by 1 each time a thread finished running, and once this variable was equal to REPEAT, the final task would run. But this didn't work. I've searched on Google and StackOverlow for answers to my problem, but there are very little informations on this and none of them worked as well. There would always be a thread that was running after the final task. How can I do this then?

like image 866
Vincent Avatar asked Nov 19 '25 00:11

Vincent


2 Answers

You can use a CountDownLatch for this. A CountDownLatch is

A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.

CountDownLatch countDownLatch = new CountDownLatch(REPEAT);
for (int i = 0; i < REPEAT; i++) {
    new Thread(new MyTask(i, countDownLatch)).start();
    Thread.sleep(1);
}
finalTask(countDownLatch);

I create a CountDownLatch whose count is initialized to the value of REPEAT. I pass this to each of the threads and to the finalTask method.

Each thread after doing its work should call the countDown method of the countDownLatch.

private static class MyTask implements Runnable {

    private int i;
    private CountDownLatch countDownLatch;

    private MyTask(int i, CountDownLatch countDownLatch) {
        this.i = i;
        this.countDownLatch = countDownLatch;
    }

    @Override
    public void run() {
        //Perform some task
        System.out.println("Running " + i);
        countDownLatch.countDown();
    }
}

The first line of the finalTask method should call the await method of the CountDownLatch. This will cause the thread running the finalTask wait till the count of the CountDownLatch reaches 0 i.e., until all threads (REPEAT number of them) has completed and invoked the countDown of the CountDownLatch.

 private static void finalTask(CountDownLatch countDownLatch) {
    try {
        countDownLatch.await(); //this will wait until the count becomes 0.
    } catch (InterruptedException e) {
        e.printStackTrace(); //handle it appropriately
    }
    //Some code to be executed once all threads stopped running
    System.out.println("All done");
}
like image 79
user7 Avatar answered Nov 21 '25 12:11

user7


Another simple way is to just join() on all the threads and then call finalTask():

Thread tasks[] = new Thread[REPEAT];

for(int i = 0; i < REPEAT; i++) {
    tasks[i] = new Thread(new MyTask(i));
    tasks[i].start();
}

for (Thread task : tasks) {
    for (;;) {
        try {
            task.join();
            break;
        }
        catch ( InterruptedException e ) {
            // catch code here
        }
    }
}

finalTask();

Note there's almost more code used to handle the possible InterruptedException from the join() method call than used to implement the rest of the processing.

like image 39
Andrew Henle Avatar answered Nov 21 '25 13:11

Andrew Henle



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!