我需要主线程来等待所有线程池任务完成。怎么做?例如: 我有程序:
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任务完成后)打印“外部”。
答案 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可以重置并再次使用。
答案 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();
}