【问题标题】:Wait main thread until all the thread pools task complete of ExecutorService?等待主线程直到ExecutorService的所有线程池任务完成?
【发布时间】:2019-10-24 15:42:29
【问题描述】:

我需要主线程等到所有线程池任务完成。怎么做?例如: 我有程序:

  public static void main(String[] args){

        ExecutorService executor = Executors.newFixedThreadPool(2);
        Map<String,String> test = new HashMap<String,String>(){{
            put("a","b");
            put("c","b");

        }};
        for(String t: test.keySet()) {
            executor.execute(new Runnable() {
                public void run() {
                    for(int i=0;i<100;i++){
                        System.out.println("t = " + t);
                    }

                }
            })
            ;
        }

        executor.shutdown();

        System.out.println("outside");;
    }

在上面的代码中,我想总是在最后打印“outside”,即在 ExecutorService 任务完成之后。

【问题讨论】:

  • executor.awaitTermination? (关机通话后)
  • awaitTermination() 期望超时参数,我想在不传递超时值的情况下这样做。有什么解决办法吗?
  • 然后以不合理的超时调用它(例如 100 年以毫秒为单位)
  • 使用 Callable 而不是 runnable。并使用 get() 或 isDone() 方法阻止。这将阻塞主线程,直到您从线程中获得结果。

标签: java multithreading


【解决方案1】:

您可以使用CountDownLatch 代替执行者。这是阻塞一个调用线程,直到它被倒计时到零。或者您可以使用CyclicBarrier。主要区别在于 CyclicBarrier 可以重置并再次使用。

CounDownLatch vs CyclicBarrier.

Simple Example CounDownLatch.

【讨论】:

    【解决方案2】:

    当使用 Executor 时,我们可以通过调用 shutdown() 或 shutdownNow() 方法来关闭它。 虽然,它不会等到所有线程停止执行。 (这就是为什么在您的代码中“外部”首先打印,而不是最后打印)。
    等待现有线程完成它们的执行可以通过使用 awaitTermination() 方法来实现,该方法会阻塞线程,直到所有任务完成执行或达到指定的超时时间

    改变

    executor.shutdown();
    

                executor.shutdown();
                try {
                    if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
                        executor.shutdownNow();
                    }
                } catch (InterruptedException ex) {
                    executor.shutdownNow();
                    Thread.currentThread().interrupt();
                }
    

    【讨论】:

      【解决方案3】:

      您正在寻找的方法正是

      <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
                                throws InterruptedException
      

      来自 javadocs,

      执行给定的任务,返回一个持有它们的 Futures 列表 全部完成时的状态和结果。 Future.isDone() 对每个都是真的 返回列表的元素。请注意,已完成的任务可能有 正常终止或抛出异常。结果 如果给定集合被修改,则此方法未定义 此操作正在进行中。

      但是,您需要将 Runnable 转换为 List&lt;Callable&lt;Void&gt;&gt; 才能使用它。

      此外,在生产中使用代码时,我会使用 Timeouts 来保持理智,该代码的方法签名为

      <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                                  long timeout,
                                  TimeUnit unit)
                                throws InterruptedException
      

      为了理智!

      【讨论】:

      • 这样,你也不必关闭执行器(如果你还需要它来做其他事情)。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-06-02
      • 2020-03-27
      • 1970-01-01
      • 2015-02-14
      • 2011-06-05
      • 2015-08-29
      • 2010-10-16
      相关资源
      最近更新 更多