1

我有一个由多个线程访问的类,每个线程请求这个类的一个方法。每个方法依次执行多个 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 来找出任务的相应结果吗?

4

3 回答 3

2

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

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

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

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

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

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

我想你想要这个:

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

希望这可以帮助。

于 2013-05-17T04:04:35.390 回答
0

对我来说,这将在课堂上同时执行任务。invokeAll()等待直到它的所有任务完成,但这是针对当前线程的,当这个线程正在等待时,其他线程可以同时执行它的任务

于 2013-05-17T04:04:31.187 回答
-1

根据 Java 规范,invokeAll所有任务同时独立地执行。并且重复调用invokeAll会做同样的事情,即调用invokeAll不阻塞任务的执行。

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

于 2013-05-17T04:03:45.243 回答