并行执行callables

时间:2011-06-14 14:41:49

标签: java multithreading callable

我想并行执行多个callables。但似乎ExecutorService总是等待所有的callables完成。

我尝试了以下内容:

final int nThreads = 10;
ExecutorService executorService = Executors.newFixedThreadPool(nThreads);
List<PrimeCallable> tasks = new ArrayList<PrimeCallable>();
for(int i = 0; i < nThreads; i++) {
    tasks.add(new PrimeCallable(0, i * 100 + 100, "thread" + i));
}

try {
    for(Future<List<Integer>> result : executorService.invokeAll(tasks)) {
        List<Integer> integers = result.get();
        for(Integer i : integers){
            System.out.println(i);
        }
    }
} catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} catch (ExecutionException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

现在,当executorService中的所有callables完成时,将调用for循环。据我所知,没有executorService.isParallel setter; - )。

让callables并行运行的正确方法是什么?

感谢您的提示!

4 个答案:

答案 0 :(得分:9)

invokeAll的javadoc说;

  

执行给定的任务,返回一个   期货持有人名单   结果全部完成。对于返回列表的每个元素,Future.isDone()都为true。

所以invokeAll阻塞,直到集合中的每个任务都完成。

答案 1 :(得分:5)

Executor服务并行运行所有可调用项。它所做的就是等待所有并行任务在继续之前完成。所以它不像所有任务都是串行运行的。

答案 2 :(得分:3)

这听起来像是你想要的 lazy 执行的一部分 - 你不想在提取结果之前在内存中复制结构。

我会将此视为迭代+转换问题。首先,在输入上定义一个迭代器,这样每次调用next()都会返回一个Callable,它将在你的系列中产生下一个值。

转换阶段是对这些Callables进行并行或并发评估,类似这样(未经测试):

public class ConcurrentTransform
{
  private final ExecutorService executor;
  private final int maxBuffer;

  public ConcurrentTransform(ExecutorService executor, int maxWorkBuffer) {
    this.executor = executor;
    this.maxBuffer = Math.max(1, maxWorkBuffer);
  }

  public <T> Iterator<T> apply(final Iterator<Callable<T>> input) {
    // track submitted work
    final BlockingQueue<Future<T>> submitted = new LinkedBlockingQueue<Future<T>>();

    // submit first N tasks
    for (int i=0; i<maxBuffer && input.hasNext(); i++) {
      Callable<T> task = input.next();
      Future<T> future = executor.submit(task);
      submitted.add(future);
    }

    return new Iterator<T>(){
      @Override
      public synchronized boolean hasNext() {
        return !submitted.isEmpty();
      }
      @Override
      public T next() {
        Future<T> result;
        synchronized (this) {
          result = submitted.poll();
          if (input.hasNext()) {
            submitted.add(executor.submit(input.next()));
          }
        }

        if (result != null) {
          try {
            return result.get(); // blocking
          } catch (Exception e) {
            if (e instanceof RuntimeException) {
               throw (RuntimeException) e;
            } else {
               throw new RuntimeException(e);
            }
          }
        } else {
          throw new NoSuchElementException();
        }
      }
      @Override
      public void remove() {
        throw new UnsupportedOperationException();
      }};
  }
}

在调用apply(...)之后,您将迭代结果值,这些值将在并行执行Callable对象并返回与输入相同的顺序。一些改进是允许阻塞result.get()调用的可选超时,或者管理变换本身内的线程池。

答案 3 :(得分:2)

如果您想要查看结果,请使用ExecutorCompletionService

相关问题