我有一个由多个线程访问的类,每个线程请求该类的一个方法。每个方法依次执行多个 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来找出任务对应的结果吗?
最佳答案
ExecutorService#invokeAll同时执行所有任务,但调用本身会阻塞,直到所有任务完成。
例如,假设您有三项任务需要 6 秒、2 秒和 10 秒才能完成。如果要同步执行这些,则至少需要 6 + 2 + 10 = 18 秒。但是,使用 invokeAll(在足够大的线程池上),这可能需要最短的时间,即 10 秒。
这意味着方法 method1()
和 method2()
都是阻塞方法,因为使用了 invokeAll()
。当您调用 method1()
时,它将阻塞,直到添加到可调用列表中的所有请求都完成为止。 method2()
也是如此。如果从不同的线程调用这些方法,则两个方法中的任务将同时执行。
如果您希望方法是异步的,您需要为方法内的每个任务单独调用 threadPool.submit(callable) 并将返回的 future 收集在列表中。您可以返回一个列表或使用 CompletionService 来帮助实现此目的,是的。
PS - 您的示例中的这一行不起作用:
ExecutorService threadPool = Runtime.getRuntime().availableProcessors();
我认为你想要这个:
ExecutorService threadPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
希望这有帮助。
关于java - invokeAll 与 CompletionService,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16601038/