如何在 运行 每个线程在 Java 中完成 运行 后执行任务?

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

我有一个循环,它在每次迭代时创建一个新线程,如下所示:

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
}

其中 MyTask 是 class 实现 Runnable。我的目标是:一旦每个线程停止,我想 运行 finalTask​​。为实现这一点,我尝试在线程每次完成 运行ning 时将变量递增 1,并且一旦该变量等于 REPEAT,最终任务将 运行。但这没有用。我在 Google 和 StackOverlow 上搜索了我的问题的答案,但是关于这个的信息很少,而且 none 的信息也有效。在最终任务之后总会有一个线程 运行ning。那我该怎么做呢?

您可以为此使用 CountDownLatch。 CountDownLatch 是

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);

我创建了一个 CountDownLatch,其 count 被初始化为 REPEAT 的值。我将其传递给每个线程和 finalTask 方法。

每个线程完成其工作后都应调用 countDownLatch 的 countDown 方法。

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();
    }
}

finalTask方法的第一行应该调用CountDownLatch的await方法。这将导致线程 运行 finalTask 等待,直到 CountDownLatch 的计数达到 0,即直到所有线程(它们的重复数)完成并调用 CountDownLatch 的 countDown

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

您可以将它们放入 CompletableFuture 中,然后使用 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
}) ;

另一种简单的方法是在所有线程上 join() 然后调用 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();

请注意,用于处理来自 join() 方法调用的可能 InterruptedException 的代码几乎多于用于实现其余处理的代码。