我需要提交一些任务,然后等待所有结果,直到所有结果都可用。它们中的每一个都向String
添加Vector
(默认情况下是同步的)。然后我需要为Vector中的每个结果启动一个新任务,但是只有当所有先前的任务都停止了它们的工作时我才需要这样做。
我想使用Java Executor,特别是我尝试使用Executors.newFixedThreadPool(100)
来使用固定数量的线程(我有一个可变数量的任务,可以是10或500)但我是新的执行者,我不知道如何等待任务终止。
这类似于我的程序需要做的伪代码:
ExecutorService e = Executors.newFixedThreadPool(100);
while(true){
/*do something*/
for(...){
<start task>
}
<wait for all task termination>
for each String in result{
<start task>
}
<wait for all task termination>
}
我不能做e.shutdown,因为我有一段时间(真实),我需要重用executorService
......
答案 0 :(得分:21)
ExecutorService
为您提供了一种机制,可以同时执行多个任务并获取Future
个对象的集合(表示任务的异步计算)。
Collection<Callable<?>> tasks = new LinkedList<Callable<?>>();
//populate tasks
for (Future<?> f : executorService.invokeAll(tasks)) { //invokeAll() blocks until ALL tasks submitted to executor complete
f.get();
}
如果您有Runnable
而不是Callable
,则可以使用以下方法轻松将Runnable
变为Callable<Object>
:
Callable<?> c = Executors.callable(runnable);
答案 1 :(得分:14)
你能给我一本指南/书吗? java executors ??
我可以回答这一部分:
Brian Goetz(Tim Peierls,Java Concurrency in Practice,Joseph Bowbeer,David Holmes和Joshua Bloch的Doug Lea最有可能是你最好的选择。
但它不仅仅是关于执行程序,而是涵盖java.util.concurrent
包,一般包括基本并发概念和技术,以及一些高级主题,如Java内存模型。< / p>
答案 2 :(得分:14)
我建议您使用Runnable
实施,而不是直接向Callable
提交Executor
或Future
并存储相应的CompletionService
返回值在完成时检索每个Future
。这种方法将任务的产生与已完成任务的消耗分离,允许例如在一段时间内在生产者线程上发起新任务。
Collection<Callable<Result>> workItems = ...
ExecutorService executor = Executors.newSingleThreadExecutor();
CompletionService<Result> compService = new ExecutorCompletionService<Result>(executor);
// Add work items to Executor.
for (Callable<Result> workItem : workItems) {
compService.submit(workItem);
}
// Consume results as they complete (this would typically occur on a different thread).
for (int i=0; i<workItems.size(); ++i) {
Future<Result> fut = compService.take(); // Will block until a result is available.
Result result = fut.get(); // Extract result; this will not block.
}
答案 3 :(得分:2)
当您提交执行服务时,您将获得Future个对象。
将这些对象存储在集合中,然后依次调用每个对象get()。 get()
阻塞,直到基础作业完成,因此结果是,一旦所有基础作业完成,就会在每个作业上调用get()
。
e.g。
Collection<Future> futures = ...
for (Future f : futures) {
Object result = f.get();
// maybe do something with the result. This could be a
// genericised Future<T>
}
System.out.println("Tasks completed");
完成所有这些后,再开始第二次提交。请注意,这可能不是您的线程池的最佳使用,因为它将变为休眠状态,然后您将重新填充它。如果可能的话,试着让它忙着做事。
答案 4 :(得分:1)
ExecutorService executor = ...
//submit tasks
executor.shutdown(); // previously submitted tasks are executed,
// but no new tasks will be accepted
while(!executor.awaitTermination(1, TimeUnit.SECONDS))
;
如果不创建自定义ExecutorService,就没有简单的方法可以做你想做的事。