等待主线程,直到ExecutorService的所有线程池任务完成?

时间:2019-06-10 08:35:46

标签: java multithreading

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

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

在上面的代码中,我想始终在最后一次(即在ExecutorService任务完成后)打印“外部”。

3 个答案:

答案 0 :(得分:1)

您正在寻找的确切方法是

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

从javadocs,

  

执行给定的任务,返回持有它们的期货的列表   全部完成时的状态和结果。 Future.isDone()对每个都适用   返回列表的元素。请注意,完成的任务可能有   正常终止或引发异常终止。结果   如果在修改给定collection的同时此方法未定义   此操作正在进行中。

但是,您需要将Runnable转换为List<Callable<Void>>才能使用它。

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

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

为保持理智!

答案 1 :(得分:0)

您可以使用CountDownLatch代替执行程序。这将阻塞一个调用线程,直到其计数到零为止。或者,您可以使用CyclicBarrier。主要区别是CyclicBarrier可以重置并再次使用。

CounDownLatch vs CyclicBarrier

Simple Example CounDownLatch

答案 2 :(得分:0)

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

更改

executor.shutdown();

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