我有一个可由多个线程访问的类,每个线程都请求此类的一个方法。每个方法依次执行许多Callables。此类使用ExecutorService中的threadPool通过invokeAll((Collection>)executeTasks)方法执行这些Callable。
设置如下所示:
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),并将返回的期货收集在列表中。您可以返回一个List或使用CompletionService来帮助实现这一点,是的。
PS-您示例中的这一行无效:
ExecutorService threadPool = Runtime.getRuntime().availableProcessors();
我认为您想要这样:
ExecutorService threadPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
希望这可以帮助。