invokeAll vs CompletionService

时间:2013-05-17 03:41:01

标签: java concurrency

我有一个由多个线程访问的类,每个线程请求此类的一个方法。每种方法依次执行多个Callables。此类使用ExecutorService中的threadPool通过invokeAll((Collection>)executableTasks)方法执行这些Callables。 设置如下:

public MyClass {
private final ExecutorService threadPool = Runtime.getRuntime().availableProcessors();

public void method1() {
 List<SomeObject> results = new ArrayList<>();
 List<Callable<Void>> tasks = new ArrayList<Callable<Void>>();
 tasks.add(new Callable<Void>(){ ... results.add(someObject);} );
 threadPool.invokeAll(tasks);
}

public void method2() {
 List<SomeObject> results = new ArrayList<>();
 List<Callable<Void>> tasks = new ArrayList<Callable<Void>>();
 tasks.add(new Callable<Void>(){ ... results.add(someObject);} );
 threadPool.invokeAll(tasks);
}

}

如果这将同时在类中执行任务或者invokeAll()将阻止执行直到一个方法中的任务完成(意味着执行将在方法内同时发生而不是在类级别),我感到困惑?或者我应该使用CompletionService来找出相应的任务结果吗?

3 个答案:

答案 0 :(得分:2)

ExecutorService#invokeAll同时执行所有任务,但调用本身会阻塞,直到所有任务完成。

例如,假设您有三个任务需要6秒,2秒和10秒才能完成。如果要同步执行这些操作,则至少需要6 + 2 + 10 = 18秒。但是,使用invokeAll(在足够大的线程池上),这可能只需要最长的时间,或10秒。

这意味着由于method1()的使用,方法method2()invokeAll()都是阻止方法。当您调用method1()时,它将阻塞,直到添加到可调用项列表中的所有请求都完成为止。同样适用于method2()。如果从不同的线程调用这些方法,则两个方法中的任务将同时执行。

如果希望方法是异步的,则需要为方法内的每个任务单独调用threadPool.submit(callable),并在列表中收集返回的future。你可以返回一个List或使用CompletionService来帮助解决这个问题,是的。

PS - 示例中的这一行不起作用:

ExecutorService threadPool = Runtime.getRuntime().availableProcessors();

我想你想要这个:

ExecutorService threadPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

希望这有帮助。

答案 1 :(得分:0)

对我来说,这将同时在类中执行任务。 invokeAll()等待所有任务完成但是当前线程正在等待,而此线程正在等待,其他线程可以同时执行其任务

答案 2 :(得分:-1)

根据Java规范invokeAll同时独立地执行所有任务。并且对invokeAll的重复调用也会这样做,也就是说,对invokeAll的调用不会阻止执行任务。

访问:http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/AbstractExecutorService.html