简体   繁体   中英

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?

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 ie, 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");
}

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.

You can put them into CompletableFuture s and then use whenComplete() .

CompletableFuture[] all =
IntStream.range(0, REPEAT+1).
  .mapToObj(i -> CompletableFuture.supplyAsync(new MyTask(i)))
  .toArray(CompletableFuture[]::new) ;
CompletableFuture.allOf(all).whenComplete((r, t) -> {
   // your code here
}) ;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM