Java执行程序:等待任务终止。

时间:2009-08-24 12:41:41

标签: java multithreading concurrency executorservice

我需要提交一些任务,然后等待所有结果,直到所有结果都可用。它们中的每一个都向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 ......

你能帮帮我吗?你能给我一本关于java执行器的指南/书吗?

5 个答案:

答案 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提交ExecutorFuture并存储相应的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,就没有简单的方法可以做你想做的事。