【问题标题】:How to run a task once every Threads finished running in Java?每个线程在 Java 中完成运行后如何运行任务?
【发布时间】:2021-04-27 18:57:01
【问题描述】:

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

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 是一个实现 Runnable 的类。我的目标是:我想在每个线程停止后运行 finalTask​​ 。为了实现这一点,我尝试在每次线程完成运行时将变量增加 1,一旦该变量等于 REPEAT,最终任务就会运行。但这没有用。我已经在 Google 和 StackOverlow 上搜索了我的问题的答案,但是这方面的信息很少,而且没有一个能正常工作。在最终任务之后总会有一个线程在运行。那我该怎么做呢?

【问题讨论】:

    标签: java multithreading runnable


    【解决方案1】:

    您可以为此使用CountDownLatch。 CountDownLatch 是

    一种同步辅助工具,允许一个或多个线程等待,直到在其他线程中执行的一组操作完成。

    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,即,直到所有线程(它们的 REPEAT 数量)都完成并调用 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");
    }
    

    【讨论】:

      【解决方案2】:

      另一种简单的方法是在所有线程上只使用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 的代码几乎比用于实现其余处理的代码多。

      【讨论】:

        【解决方案3】:

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

        【讨论】:

        • CompletableFuture.submit?
        猜你喜欢
        • 2021-06-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-12
        • 2015-04-09
        • 1970-01-01
        • 2016-05-24
        相关资源
        最近更新 更多